diff --git a/.gitignore b/.gitignore
index 7393e2aa5..8927de757 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
.idea
*~
*.swp
+HTML
\ No newline at end of file
diff --git a/db/manifest b/db/manifest
index c56e9d29b..94d24481b 100755
--- a/db/manifest
+++ b/db/manifest
@@ -74,4 +74,5 @@ crash_dumps_idx.sql
music_sessions_user_history_add_session_removed_at.sql
user_progress_tracking.sql
whats_next.sql
+add_user_bio.sql
users_geocoding.sql
diff --git a/db/up/add_user_bio.sql b/db/up/add_user_bio.sql
new file mode 100644
index 000000000..725ff5b70
--- /dev/null
+++ b/db/up/add_user_bio.sql
@@ -0,0 +1 @@
+alter table users add column biography VARCHAR(4000);
\ No newline at end of file
diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb
index 05f0d4645..d853050b7 100644
--- a/ruby/lib/jam_ruby/models/band.rb
+++ b/ruby/lib/jam_ruby/models/band.rb
@@ -61,6 +61,10 @@ module JamRuby
BandMusician.create(:band_id => self.id, :user_id => user_id, :admin => admin)
end
+ def self.musician_index(band_id)
+ @musicians = User.joins(:band_musicians).where(:bands_musicians => {:band_id => "#{band_id}"})
+ end
+
def self.recording_index(current_user, band_id)
hide_private = false
band = Band.find(band_id)
diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb
index f35c55862..35cf1e2a2 100644
--- a/ruby/lib/jam_ruby/models/user.rb
+++ b/ruby/lib/jam_ruby/models/user.rb
@@ -426,7 +426,7 @@ module JamRuby
# this easy_save routine guards against nil sets, but many of these fields can be set to null.
# I've started to use it less as I go forward
def easy_save(first_name, last_name, email, password, password_confirmation, musician, gender,
- birth_date, internet_service_provider, city, state, country, instruments, photo_url)
+ birth_date, internet_service_provider, city, state, country, instruments, photo_url, biography = nil)
# first name
unless first_name.nil?
@@ -499,13 +499,17 @@ module JamRuby
self.photo_url = photo_url
end
+ unless biography.nil?
+ self.biography = biography
+ end
+
self.updated_at = Time.now.getutc
self.save
end
# helper method for creating / updating a User
def self.save(id, updater_id, first_name, last_name, email, password, password_confirmation, musician, gender,
- birth_date, internet_service_provider, city, state, country, instruments, photo_url)
+ birth_date, internet_service_provider, city, state, country, instruments, photo_url, biography)
if id.nil?
user = User.new()
else
@@ -517,7 +521,7 @@ module JamRuby
end
user.easy_save(first_name, last_name, email, password, password_confirmation, musician, gender,
- birth_date, internet_service_provider, city, state, country, instruments, photo_url)
+ birth_date, internet_service_provider, city, state, country, instruments, photo_url, biography)
return user
end
diff --git a/web/app/assets/images/content/icon_followers.png b/web/app/assets/images/content/icon_followers.png
new file mode 100644
index 000000000..957258ceb
Binary files /dev/null and b/web/app/assets/images/content/icon_followers.png differ
diff --git a/web/app/assets/images/content/icon_friend.png b/web/app/assets/images/content/icon_friend.png
new file mode 100644
index 000000000..fd4aaa0d4
Binary files /dev/null and b/web/app/assets/images/content/icon_friend.png differ
diff --git a/web/app/assets/images/content/icon_recordings.png b/web/app/assets/images/content/icon_recordings.png
new file mode 100644
index 000000000..b530b2b69
Binary files /dev/null and b/web/app/assets/images/content/icon_recordings.png differ
diff --git a/web/app/assets/images/content/icon_session_tiny.png b/web/app/assets/images/content/icon_session_tiny.png
new file mode 100644
index 000000000..180cf2d66
Binary files /dev/null and b/web/app/assets/images/content/icon_session_tiny.png differ
diff --git a/web/app/assets/javascripts/alert.js b/web/app/assets/javascripts/alert.js
index 077240d4e..7ba13363c 100644
--- a/web/app/assets/javascripts/alert.js
+++ b/web/app/assets/javascripts/alert.js
@@ -10,7 +10,9 @@
function events() {
$('#btn-alert-ok').unbind("click");
$('#btn-alert-ok').click(function(evt) {
- callback(sessionId);
+ if (callback) {
+ callback(sessionId);
+ }
});
$('#btn-alert-cancel').unbind("click");
diff --git a/web/app/assets/javascripts/bandProfile.js b/web/app/assets/javascripts/bandProfile.js
new file mode 100644
index 000000000..d03ce3bdf
--- /dev/null
+++ b/web/app/assets/javascripts/bandProfile.js
@@ -0,0 +1,419 @@
+(function(context,$) {
+
+ "use strict";
+
+ context.JK = context.JK || {};
+ context.JK.BandProfileScreen = function(app) {
+ var logger = context.JK.logger;
+ var bandId;
+ var band = {};
+ var instrument_logo_map = context.JK.getInstrumentIconMap24();
+
+ function beforeShow(data) {
+ bandId = data.id;
+ }
+
+ function afterShow(data) {
+ resetForm();
+ events();
+ renderActive();
+ }
+
+ function resetForm() {
+ $('#band-profile-instruments').empty();
+
+ $('#band-profile-about').show();
+ $('#band-profile-history').hide();
+ $('#band-profile-members').hide();
+ $('#band-profile-social').hide();
+
+ $('.band-profile-nav a.active').removeClass('active');
+ $('.band-profile-nav a.#band-profile-about-link').addClass('active');
+ }
+
+ /****************** MAIN PORTION OF SCREEN *****************/
+
+ function addFollowing(isBand, id) {
+ var newFollowing = {};
+
+ if (!isBand) {
+ newFollowing.user_id = id;
+ }
+ else {
+ newFollowing.band_id = id;
+ }
+
+ var url = "/api/users/" + context.JK.currentUserId + "/followings";
+ $.ajax({
+ type: "POST",
+ dataType: "json",
+ contentType: 'application/json',
+ url: url,
+ data: JSON.stringify(newFollowing),
+ processData: false,
+ success: function(response) {
+ renderActive(); // refresh stats
+ if (isBand) {
+ configureBandFollowingButton(true);
+ }
+ else {
+ configureMemberFollowingButton(true);
+ }
+ },
+ error: app.ajaxError
+ });
+ }
+
+ function removeFollowing(isBand, id) {
+ var following = {};
+ if (!isBand) {
+ following.user_id = id;
+ }
+ else {
+ following.band_id = id;
+ }
+
+ var url = "/api/users/" + context.JK.currentUserId + "/followings";
+ $.ajax({
+ type: "DELETE",
+ dataType: "json",
+ contentType: 'application/json',
+ url: url,
+ data: JSON.stringify(following),
+ processData: false,
+ success: function(response) {
+ renderActive(); // refresh stats
+ if (isBand) {
+ configureBandFollowingButton(false);
+ }
+ else {
+ configureMemberFollowingButton(false, id);
+ }
+ },
+ error: app.ajaxError
+ });
+ }
+
+ function isFollowingMember(userId) {
+ var alreadyFollowing = false;
+
+ var url = "/api/users/" + context.JK.currentUserId + "/followings/" + userId;
+ $.ajax({
+ type: "GET",
+ dataType: "json",
+ url: url,
+ async: false,
+ processData: false,
+ success: function(response) {
+ if (response.id !== undefined) {
+ alreadyFollowing = true;
+ }
+ else {
+ alreadyFollowing = false;
+ }
+ },
+ error: app.ajaxError
+ });
+
+ return alreadyFollowing;
+ }
+
+ function isFollowing() {
+ var alreadyFollowing = false;
+
+ var url = "/api/users/" + context.JK.currentUserId + "/band_followings/" + bandId;
+ $.ajax({
+ type: "GET",
+ dataType: "json",
+ url: url,
+ async: false,
+ processData: false,
+ success: function(response) {
+ if (response.id !== undefined) {
+ alreadyFollowing = true;
+ }
+ else {
+ alreadyFollowing = false;
+ }
+ },
+ error: app.ajaxError
+ });
+
+ return alreadyFollowing;
+ }
+
+ function configureBandFollowingButton(following) {
+ $('#btn-follow-band').unbind("click");
+
+ if (following) {
+ $('#btn-follow-band').text('STOP FOLLOWING');
+ $('#btn-follow-band').click(function() {
+ removeFollowing(true, bandId);
+ });
+ }
+ else {
+ $('#btn-follow-band').text('FOLLOW');
+ $('#btn-follow-band').click(function() {
+ addFollowing(true, bandId);
+ });
+ }
+ }
+
+ function configureMemberFollowingButton(following, userId) {
+ var $btnFollowMember = $('div[user-id=' + userId + ']', '#band-profile-members').find('#btn-follow-member');
+ $btnFollowMember.unbind("click");
+
+ if (following) {
+ $btnFollowMember.text('UN-FOLLOW');
+ $btnFollowMember.click(function() {
+ removeFollowing(false, userId);
+ });
+ }
+ else {
+ $btnFollowMember.text('FOLLOW');
+ $btnFollowMember.click(function() {
+ addFollowing(false, userId);
+ });
+ }
+ }
+
+ // refreshes the currently active tab
+ function renderActive() {
+ if ($('#band-profile-about-link').hasClass('active')) {
+ renderAbout();
+ }
+ else if ($('#band-profile-history-link').hasClass('active')) {
+ renderHistory();
+ }
+ else if ($('#band-profile-members-link').hasClass('active')) {
+ renderMembers();
+ }
+ else if ($('#band-profile-social-link').hasClass('active')) {
+ renderSocial();
+ }
+ }
+
+ /****************** ABOUT TAB *****************/
+ function renderAbout() {
+
+ $('#band-profile-about').show();
+ $('#band-profile-history').hide();
+ $('#band-profile-members').hide();
+ $('#band-profile-social').hide();
+
+ $('.band-profile-nav a.active').removeClass('active');
+ $('.band-profile-nav a.#band-profile-about-link').addClass('active');
+
+ bindAbout();
+ }
+
+ function bindAbout() {
+ var url = "/api/bands/" + bandId;
+ $.ajax({
+ type: "GET",
+ dataType: "json",
+ url: url,
+ async: false,
+ processData:false,
+ success: function(response) {
+ band = response;
+ },
+ error: app.ajaxError
+ });
+
+ if (band) {
+
+ // name
+ $('#band-profile-name').html(band.name);
+
+ // avatar
+ $('#band-profile-avatar').attr('src', context.JK.resolveAvatarUrl(band.photo_url));
+
+ // location
+ $('#band-profile-location').html(band.location);
+
+ // stats
+ var text = band.follower_count > 1 || band.follower_count == 0 ? " Followers" : " Follower";
+ $('#band-profile-follower-stats').html(band.follower_count + text);
+
+ text = band.session_count > 1 || band.session_count == 0 ? " Sessions" : " Session";
+ $('#band-profile-session-stats').html(band.session_count + text);
+
+ text = band.recording_count > 1 || band.recording_count == 0 ? " Recordings" : " Recording";
+ $('#band-profile-recording-stats').html(band.recording_count + text);
+
+ $('#band-profile-biography').html(band.biography);
+ }
+ else {
+
+ }
+ }
+
+ /****************** SOCIAL TAB *****************/
+ function renderSocial() {
+ $('#band-profile-social-followers').empty();
+
+ $('#band-profile-about').hide();
+ $('#band-profile-history').hide();
+ $('#band-profile-members').hide();
+ $('#band-profile-social').show();
+
+ $('.band-profile-nav a.active').removeClass('active');
+ $('.band-profile-nav a.#band-profile-social-link').addClass('active');
+
+ bindSocial();
+ }
+
+ function bindSocial() {
+ // FOLLOWERS
+ url = "/api/bands/" + bandId + "/followers";
+ $.ajax({
+ type: "GET",
+ dataType: "json",
+ url: url,
+ async: false,
+ processData:false,
+ success: function(response) {
+ $.each(response, function(index, val) {
+ var template = $('#template-band-profile-social').html();
+ var followerHtml = context.JK.fillTemplate(template, {
+ avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
+ userName: val.name,
+ location: val.location
+ });
+
+ $('#band-profile-social-followers').append(followerHtml);
+ });
+ },
+ error: app.ajaxError
+ });
+ }
+
+ /****************** HISTORY TAB *****************/
+ function renderHistory() {
+ $('#band-profile-about').hide();
+ $('#band-profile-history').show();
+ $('#band-profile-members').hide();
+ $('#band-profile-social').hide();
+
+ $('.band-profile-nav a.active').removeClass('active');
+ $('.band-profile-nav a.#band-profile-history-link').addClass('active');
+
+ bindHistory();
+ }
+
+ function bindHistory() {
+
+ }
+
+ /****************** BANDS TAB *****************/
+ function renderMembers() {
+ $('#band-profile-members').empty();
+
+ $('#band-profile-about').hide();
+ $('#band-profile-history').hide();
+ $('#band-profile-members').show();
+ $('#band-profile-social').hide();
+
+ $('.band-profile-nav a.active').removeClass('active');
+ $('.band-profile-nav a.#band-profile-members-link').addClass('active');
+
+ bindMembers();
+ }
+
+ function bindMembers() {
+ var url = "/api/bands/" + bandId + "/musicians";
+ $.ajax({
+ type: "GET",
+ dataType: "json",
+ url: url,
+ async: false,
+ processData:false,
+ success: function(response) {
+ $.each(response, function(index, val) {
+ var instrumentLogoHtml = '';
+ var musician = val;
+ if ("instruments" in musician) {
+ 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 += ' ';
+ }
+ }
+
+ var template = $('#template-band-profile-members').html();
+ var memberHtml = context.JK.fillTemplate(template, {
+ userId: musician.id,
+ profile_url: "/#/profile/" + musician.id,
+ avatar_url: context.JK.resolveAvatarUrl(musician.photo_url),
+ name: musician.name,
+ location: musician.location,
+ biography: musician.biography,
+ friend_count: musician.friend_count,
+ follower_count: musician.follower_count,
+ recording_count: musician.recording_count,
+ session_count: musician.session_count,
+ instruments: instrumentLogoHtml
+ });
+
+ $('#band-profile-members').append(memberHtml);
+
+ // wire up Follow button click handler
+ var following = isFollowingMember(musician.id);
+ configureMemberFollowingButton(following, musician.id);
+
+ // TODO: wire up Friend button click handler
+ // var friend = isFriend(musician.id);
+ // configureMemberFriendButton(friend, musician.id);
+ });
+ },
+ error: app.ajaxError
+ });
+ }
+
+ 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;
+ }
+
+ // events for main screen
+ function events() {
+ // wire up panel clicks
+ $('#band-profile-about-link').click(renderAbout);
+ $('#band-profile-history-link').click(renderHistory);
+ $('#band-profile-members-link').click(renderMembers);
+ $('#band-profile-social-link').click(renderSocial);
+
+ // wire up Follow click
+ var following = isFollowing();
+ configureBandFollowingButton(following);
+ }
+
+ function initialize() {
+ var screenBindings = {
+ 'beforeShow': beforeShow,
+ 'afterShow': afterShow
+ };
+ app.bindScreen('bandProfile', screenBindings);
+ }
+
+
+ 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/configureTrack.js b/web/app/assets/javascripts/configureTrack.js
index 01b32d7c5..c2d9b8fb0 100644
--- a/web/app/assets/javascripts/configureTrack.js
+++ b/web/app/assets/javascripts/configureTrack.js
@@ -696,7 +696,7 @@
function validateAudioSettings(allowEmptyInput) {
var isValid = true;
- var noTrackErrMsg = 'You must assign at least one input port to each of your tracks. Please update your settings to correct this.';
+ var noTrackErrMsg = 'You can assign no more than 2 input ports to each of your tracks. Please update your settings to correct this.';
var noInstrumentErrMsg = 'You must specify what instrument is being played for each track. Please update your settings to correct this.';
var outputErrMsg = 'You must assign two output ports for stereo session audio to hear music. Please update your settings to correct this.';
@@ -725,12 +725,14 @@
// if Track 2 exists, verify Input and Instrument exist
if (isValid) {
- if ($('#track2-input > option').size() > 2) {
+ var track2Count = $('#track2-input > option').size();
+ if (track2Count > 2) {
errMsg = noTrackErrMsg;
isValid = false;
}
- if (isValid && $('#track2-instrument > option:selected').length === 0) {
+ // only validate instrument if second track is selected
+ if (isValid && track2Count > 0 && $('#track2-instrument > option:selected').length === 0) {
errMsg = noInstrumentErrMsg;
isValid = false;
}
diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js
index 3268d1834..fc69c53bc 100644
--- a/web/app/assets/javascripts/profile.js
+++ b/web/app/assets/javascripts/profile.js
@@ -8,6 +8,8 @@
var userId;
var user = {};
+ var instrument_logo_map = context.JK.getInstrumentIconMap24();
+
var proficiencyDescriptionMap = {
"1": "BEGINNER",
"2": "INTERMEDIATE",
@@ -317,7 +319,7 @@
text = user.recording_count > 1 || user.recording_count == 0 ? " Recordings" : " Recording";
$('#profile-recording-stats').html(user.recording_count + text);
- //$('#profile-biography').html(user.biography);
+ $('#profile-biography').html(user.biography);
}
else {
@@ -481,20 +483,53 @@
processData:false,
success: function(response) {
$.each(response, function(index, val) {
- var template = $('#template-profile-bands').html();
- var bandHtml = context.JK.fillTemplate(template, {
- bandId: val.id,
- avatar_url: context.JK.resolveAvatarUrl(val.logo_url),
- name: val.name,
- location: val.location,
- genres: formatGenres(val.genres)
- });
- $('#profile-bands').append(bandHtml);
+ // build band member HTML
+ var musicianHtml = '';
+ if ("musicians" in val) {
+ for (var i=0; i < val.musicians.length; i++) {
+ var musician = val.musicians[i];
+ var instrumentLogoHtml = '';
+ if ("instruments" in musician) {
+ 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, {
+ avatar_url: context.JK.resolveAvatarUrl(musician.photo_url),
+ profile_url: "/#/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: "/#/bandProfile/" + val.id,
+ avatar_url: context.JK.resolveAvatarUrl(val.logo_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
+ });
- // wire up Band Follow button click handler
- var following = isFollowingBand(val.id);
- configureBandFollowingButton(following, val.id);
+ $('#profile-bands').append(bandHtml);
+
+ // wire up Band Follow button click handler
+ var following = isFollowingBand(val.id);
+ configureBandFollowingButton(following, val.id);
});
},
error: app.ajaxError
@@ -503,11 +538,13 @@
function formatGenres(genres) {
var formattedGenres = '';
- for (var i=0; i < genres.length; i++) {
- var genre = genres[i];
- formattedGenres += genre.description;
- if (i < genres.length -1) {
- 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;
@@ -515,7 +552,7 @@
function addBandFollowing(evt) {
evt.stopPropagation();
- var bandId = $(this).parent().attr('band-id');
+ var bandId = $(this).parent().parent().attr('band-id');
var newFollowing = {};
newFollowing.band_id = bandId;
@@ -529,7 +566,7 @@
data: JSON.stringify(newFollowing),
processData: false,
success: function(response) {
- renderActive(); // refresh stats
+ renderBands(); // refresh stats
configureBandFollowingButton(true, bandId);
},
error: app.ajaxError
diff --git a/web/app/assets/javascripts/sessionList.js b/web/app/assets/javascripts/sessionList.js
index 131c987aa..49af23e00 100644
--- a/web/app/assets/javascripts/sessionList.js
+++ b/web/app/assets/javascripts/sessionList.js
@@ -137,19 +137,69 @@
// wire up the Join Link to the T&Cs dialog
var $parentRow = $('tr[id=' + session.id + ']', tbGroup);
- if (session.approval_required) {
- $('#join-link', $parentRow).click(function(evt) {
- openAlert(session.id);
- });
- }
- else {
- $('#join-link', $parentRow).click(function(evt) {
- openTerms(session.id);
- });
- }
+ $('#join-link', $parentRow).click(function(evt) {
+ joinClick(session.id);
+ });
}
}
+ function joinClick(sessionId) {
+ var hasInvitation = false;
+ var session = null;
+ // we need to do a real-time check of the session in case the settings have
+ // changed while the user was sitting on the Find Session screen
+ $.ajax({
+ type: "GET",
+ url: "/api/sessions/" + sessionId,
+ async: false,
+ success: function(response) {
+ session = response;
+ if ("invitations" in session) {
+ var invitation;
+ // user has invitations for this session
+ for (var i=0; i < session.invitations.length; i++) {
+ invitation = session.invitations[i];
+ // session contains an invitation for this user
+ if (invitation.receiver_id === context.JK.currentUserId) {
+ hasInvitation = true;
+ }
+ }
+ }
+
+ if (session) {
+ // if user has an invitation, always open terms and allow joining regardless of settings
+ if (hasInvitation) {
+ logger.debug("Found invitation for user " + context.JK.currentUserId + ", session " + sessionId);
+ openTerms(sessionId);
+ }
+ else {
+ if (session.musician_access) {
+ if (session.approval_required) {
+ openAlert(sessionId);
+ }
+ else {
+ openTerms(sessionId);
+ }
+ }
+ }
+ }
+ },
+ error: function(xhr, textStatus, errorMessage) {
+ logger.debug("xhr.status = " + xhr.status);
+ if (xhr.status === 404) {
+ sessionNotJoinableAlert();
+ }
+ else {
+ app.notify(
+ { title: "Unable to Join Session",
+ text: "There was an unexpected error while attempting to join the session."
+ },
+ { no_cancel: true });
+ }
+ }
+ });
+ }
+
function openAlert(sessionId) {
var alertDialog = new context.JK.AlertDialog(app, "YES",
"You must be approved to join this session. Would you like to send a request to join?",
@@ -159,6 +209,19 @@
app.layout.showDialog('alert');
}
+ function sessionNotJoinableAlert() {
+ var alertDialog = new context.JK.AlertDialog(app, "OK",
+ "This session is over or is no longer public and cannot be joined. Please click Refresh to update the session list.",
+ null,
+ function(evt) {
+ app.layout.closeDialog('alert');
+ }
+ );
+
+ alertDialog.initialize();
+ app.layout.showDialog('alert');
+ }
+
function onCreateJoinRequest(sessionId) {
var joinRequest = {};
joinRequest.music_session = sessionId;
diff --git a/web/app/assets/stylesheets/client/bandProfile.css.scss b/web/app/assets/stylesheets/client/bandProfile.css.scss
new file mode 100644
index 000000000..d1ab30b9c
--- /dev/null
+++ b/web/app/assets/stylesheets/client/bandProfile.css.scss
@@ -0,0 +1,218 @@
+@import "client/common.css.scss";
+
+.band-profile-header {
+ padding:20px;
+ height:120px;
+}
+
+.band-profile-header h2 {
+ font-weight:200;
+ font-size: 28px;
+ float:left;
+ margin: 0px 150px 0px 0px;
+}
+
+.band-profile-status {
+ font-size:12px;
+ float:left;
+ display:inline-block;
+ vertical-align:middle;
+ line-height:30px;
+}
+
+.band-profile-photo {
+ height: 95px;
+ width: 15%;
+ float:left;
+}
+
+.band-profile-nav {
+ width:85%;
+ position:relative;
+ float:right;
+ margin-right:-10px;
+}
+
+.band-profile-nav a {
+ width:24%;
+ text-align:center;
+ height: 27px;
+ display: block;
+ float:left;
+ margin-right:5px;
+ vertical-align:bottom;
+ padding-top:65px;
+ background-color:#535353;
+ color:#ccc;
+ font-size:17px;
+ text-decoration:none;
+}
+
+.band-profile-nav a:hover {
+ background-color:#666;
+ color:#fff;
+}
+
+.band-profile-nav a.active {
+ background-color:#ed3618;
+ color:#fff;
+}
+
+.band-profile-nav a.active:hover {
+ background-color:#ed3618;
+ cursor:default;
+}
+
+.band-profile-nav a.last {
+ margin-right:0px !important;
+}
+
+.avatar-profile {
+ float:left;
+ padding:2px;
+ width:88px;
+ height:88px;
+ background-color:#ed3618;
+ -webkit-border-radius:44px;
+ -moz-border-radius:44px;
+ border-radius:44px;
+}
+
+.avatar-profile img {
+ width:88px;
+ height:88px;
+ -webkit-border-radius:44px;
+ -moz-border-radius:44px;
+ border-radius:44px;
+}
+
+.band-profile-wrapper {
+ padding:10px 25px 10px 25px;
+ font-size:15px;
+ color:#ccc;
+ border-bottom: dotted 1px #444;
+ position:relative;
+ display:block;
+}
+
+.band-profile-about-left {
+ width:16%;
+ float:left;
+ font-size:13px;
+ line-height:140%;
+ display:block;
+}
+
+.band-profile-about-left h3 {
+ color:#fff;
+ margin-bottom:0px;
+ font-size:13px;
+ font-weight:bold;
+ display:inline;
+}
+
+.band-profile-about-right {
+ float:right;
+ font-size:13px;
+ width:84%;
+ line-height:140%;
+ display:block;
+}
+
+.band-profile-about-right .band-profile-instrument {
+ text-align:center;
+ margin-right:15px;
+ float:left;
+}
+
+.proficiency-beginner {
+ font-size:10px;
+ color:#8ea415;
+ font-weight:600;
+}
+
+.proficiency-intermediate {
+ font-size:10px;
+ color:#0b6672;
+ font-weight:600;
+}
+
+.proficiency-expert {
+ font-size:10px;
+ color:#ed3618;
+ font-weight:600;
+}
+
+.band-profile-members {
+ width:100%;
+ min-height:90px;
+ background-color:#242323;
+ position:relative;
+ float:left;
+ margin:10px 20px 10px 0px;
+ padding-bottom:5px;
+}
+
+.band-profile-member-name {
+ float:left;
+ font-size:12px;
+ margin-top:12px;
+ font-weight:bold;
+}
+
+.band-profile-member-location {
+ font-size:12px;
+ font-weight:200;
+}
+
+.band-profile-member-genres {
+ float:left;
+ width:40%;
+ font-size:10px;
+ margin-left:10px;
+ padding-right:5px;
+}
+
+.band-profile-social-left {
+ float:left;
+ width:32%;
+ margin-right:12px;
+ border-right:solid 1px #666;
+}
+
+.band-profile-social-mid {
+ float:left;
+ width:31%;
+ margin-right:12px;
+ border-right:solid 1px #666;
+}
+
+.band-profile-social-right {
+ float:left;
+ width:31%;
+}
+
+.band-profile-social-left h2, .band-profile-social-mid h2, .band-profile-social-right h2 {
+ font-weight:200;
+ color:#fff;
+ font-size:20px;
+}
+
+.band-profile-block {
+ clear:left;
+ white-space:nowrap;
+ display:block;
+ margin-bottom:10px;
+}
+
+.band-profile-block-name {
+ display:inline-block;
+ margin-top:13px;
+ font-size:14px;
+ color:#fff;
+ font-weight:bold;
+}
+
+.band-profile-block-city {
+ font-size:12px;
+}
diff --git a/web/app/assets/stylesheets/client/client.css b/web/app/assets/stylesheets/client/client.css
index fd8e50ffa..54b1d6db8 100644
--- a/web/app/assets/stylesheets/client/client.css
+++ b/web/app/assets/stylesheets/client/client.css
@@ -22,6 +22,7 @@
*= require ./sidebar
*= require ./home
*= require ./profile
+ *= require ./bandProfile
*= require ./findSession
*= require ./session
*= require ./account
diff --git a/web/app/assets/stylesheets/client/content.css.scss b/web/app/assets/stylesheets/client/content.css.scss
index 228a6edf2..6a23a30a8 100644
--- a/web/app/assets/stylesheets/client/content.css.scss
+++ b/web/app/assets/stylesheets/client/content.css.scss
@@ -1,271 +1,271 @@
/* This is simply Jeff's content.css file */
@charset "UTF-8";
#content {
- background-color: #353535;
- border: 1px solid #ed3618;
- clear: both;
- float: left;
- margin-top: 39px;
- height: auto;
- width: auto;
- position:relative;
- padding-bottom:3px;
+ background-color: #353535;
+ border: 1px solid #ed3618;
+ clear: both;
+ float: left;
+ margin-top: 39px;
+ height: auto;
+ width: auto;
+ position:relative;
+ padding-bottom:3px;
}
.content-head {
- height:21px;
- padding:4px;
- background-color:#ED3618;
+ height:21px;
+ padding:4px;
+ background-color:#ED3618;
}
.content-icon {
- margin-right:10px;
- float:left;
+ margin-right:10px;
+ float:left;
}
.content-head h1 {
- margin: -6px 0px 0px 0px;
- padding:0;
- float:left;
- font-weight:100;
- font-size:24px;
+ margin: -6px 0px 0px 0px;
+ padding:0;
+ float:left;
+ font-weight:100;
+ font-size:24px;
}
.content-nav {
- float:right;
- margin-right:10px;
+ float:right;
+ margin-right:10px;
}
.home-icon {
- float:left;
- margin-right:20px;
+ float:left;
+ margin-right:20px;
}
.content-nav a.arrow-right {
- float:left;
- display:block;
- margin-top:2px;
- margin-right:10px;
- width: 0;
- height: 0;
- border-top: 7px solid transparent;
- border-bottom: 7px solid transparent;
- border-left: 7px solid #FFF;
+ float:left;
+ display:block;
+ margin-top:2px;
+ margin-right:10px;
+ width: 0;
+ height: 0;
+ border-top: 7px solid transparent;
+ border-bottom: 7px solid transparent;
+ border-left: 7px solid #FFF;
}
.content-nav a.arrow-left {
- float:left;
- display:block;
- margin-top:2px;
- margin-right:20px;
- width: 0;
- height: 0;
- border-top: 7px solid transparent;
- border-bottom: 7px solid transparent;
- border-right:7px solid #FFF;
+ float:left;
+ display:block;
+ margin-top:2px;
+ margin-right:20px;
+ width: 0;
+ height: 0;
+ border-top: 7px solid transparent;
+ border-bottom: 7px solid transparent;
+ border-right:7px solid #FFF;
}
#content-scroller, .content-scroller {
- height:inherit;
- position:relative;
- display:block;
- overflow:auto;
+ height:inherit;
+ position:relative;
+ display:block;
+ overflow:auto;
}
.content-wrapper {
- padding:10px 30px 10px 36px;
- font-size:15px;
- color:#ccc;
- border-bottom: dotted 1px #444;
- overflow-x:hidden;
- white-space:nowrap;
+ padding:10px 30px 10px 36px;
+ font-size:15px;
+ color:#ccc;
+ border-bottom: dotted 1px #444;
+ overflow-x:hidden;
+ white-space:nowrap;
}
.create-session-left {
- width:50%;
- float:left;
+ width:50%;
+ float:left;
}
.create-session-right {
- width:45%;
- float:right;
- font-size:13px;
+ width:45%;
+ float:right;
+ font-size:13px;
}
.content-wrapper h2 {
- color:#fff;
- font-weight:600;
- font-size:24px;
+ color:#fff;
+ font-weight:600;
+ font-size:24px;
}
.content-wrapper select, .content-wrapper textarea, .content-wrapper input[type=text], .content-wrapper input[type=password], div.friendbox, .ftue-inner input[type=text], .ftue-inner input[type=password], .dialog-inner textarea, .dialog-inner input[type=text] {
- font-family:"Raleway", arial, sans-serif;
- background-color:#c5c5c5;
- border:none;
- -webkit-box-shadow: inset 2px 2px 3px 0px #888;
- box-shadow: inset 2px 2px 3px 0px #888;
- color:#666;
+ font-family:"Raleway", arial, sans-serif;
+ background-color:#c5c5c5;
+ border:none;
+ -webkit-box-shadow: inset 2px 2px 3px 0px #888;
+ box-shadow: inset 2px 2px 3px 0px #888;
+ color:#666;
}
.create-session-description {
- padding:5px;
- width:100%;
- height:80px;
+ padding:5px;
+ width:100%;
+ height:80px;
}
.friendbox {
- padding:5px;
- width:100%;
- height:60px;
+ padding:5px;
+ width:100%;
+ height:60px;
}
.invite-friend {
- margin:0px 4px 4px 4px;
- float:left;
- display:block;
- background-color:#666;
- color:#fff;
- font-size:12px;
- -webkit-border-radius: 7px;
- border-radius: 7px;
- padding:2px 2px 2px 4px;
+ margin:0px 4px 4px 4px;
+ float:left;
+ display:block;
+ background-color:#666;
+ color:#fff;
+ font-size:12px;
+ -webkit-border-radius: 7px;
+ border-radius: 7px;
+ padding:2px 2px 2px 4px;
}
.content-wrapper div.friendbox input[type=text] {
- -webkit-box-shadow: inset 0px 0px 0px 0px #888;
- box-shadow: inset 0px 0px 0px 0px #888;
- color:#666;
- font-style:italic;
+ -webkit-box-shadow: inset 0px 0px 0px 0px #888;
+ box-shadow: inset 0px 0px 0px 0px #888;
+ color:#666;
+ font-style:italic;
}
#genrelist, #musicianlist {
- position:relative;
- z-index:99;
- width: 175px;
- -webkit-border-radius: 6px;
- border-radius: 6px;
- background-color:#C5C5C5;
- border: none;
- color:#333;
- font-weight:400;
- padding:0px 0px 0px 8px;
- height:20px;
- line-height:20px;
- overflow:hidden;
- -webkit-box-shadow: inset 2px 2px 3px 0px #888;
- box-shadow: inset 2px 2px 3px 0px #888;
+ position:relative;
+ z-index:99;
+ width: 175px;
+ -webkit-border-radius: 6px;
+ border-radius: 6px;
+ background-color:#C5C5C5;
+ border: none;
+ color:#333;
+ font-weight:400;
+ padding:0px 0px 0px 8px;
+ height:20px;
+ line-height:20px;
+ overflow:hidden;
+ -webkit-box-shadow: inset 2px 2px 3px 0px #888;
+ box-shadow: inset 2px 2px 3px 0px #888;
}
#musicianlist, .session-controls #genrelist {
- width: 150px;
+ width: 150px;
}
#genrelist a, #musicianlist a {
- color:#333;
- text-decoration:none;
+ color:#333;
+ text-decoration:none;
}
.genre-wrapper, .musician-wrapper {
- float:left;
- width:175px;
- height:127px;
- overflow:auto;
+ float:left;
+ width:175px;
+ height:127px;
+ overflow:auto;
}
.musician-wrapper, .session-controls .genre-wrapper {
- width:150px;
+ width:150px;
}
.genrecategory {
- font-size:11px;
- float:left;
- width:135px;
+ font-size:11px;
+ float:left;
+ width:135px;
}
.filtercategory, .session-controls .genrecategory {
- font-size:11px;
- float:left;
- width:110px;
+ font-size:11px;
+ float:left;
+ width:110px;
}
a.arrow-up {
- float:right;
- margin-right:5px;
- display:block;
- margin-top:6px;
- width: 0;
- height: 0;
- border-left: 7px solid transparent;
- border-right: 7px solid transparent;
- border-bottom: 7px solid #333;
+ float:right;
+ margin-right:5px;
+ display:block;
+ margin-top:6px;
+ width: 0;
+ height: 0;
+ border-left: 7px solid transparent;
+ border-right: 7px solid transparent;
+ border-bottom: 7px solid #333;
}
a.arrow-down {
- float:right;
- margin-right:5px;
- display:block;
- margin-top:6px;
- width: 0;
- height: 0;
- border-left: 7px solid transparent;
- border-right: 7px solid transparent;
- border-top: 7px solid #333;
+ float:right;
+ margin-right:5px;
+ display:block;
+ margin-top:6px;
+ width: 0;
+ height: 0;
+ border-left: 7px solid transparent;
+ border-right: 7px solid transparent;
+ border-top: 7px solid #333;
}
.settings-session-description {
- padding:10px;
- width:300px;
+ padding:10px;
+ width:300px;
}
#session-controls {
- width:100%;
- padding:11px 0px 11px 0px;
- background-color:#4c4c4c;
- min-height:20px;
- overflow-x:hidden;
- }
+ width:100%;
+ padding:11px 0px 11px 0px;
+ background-color:#4c4c4c;
+ min-height:20px;
+ overflow-x:hidden;
+ }
#session-controls .searchbox {
- float:left;
- width:140px;
- margin-left: 10px;
- -webkit-border-radius: 6px;
- border-radius: 6px;
- background-color:#C5C5C5;
- border: none;
- color:#333;
- font-weight:400;
- padding:0px 0px 0px 8px;
- height:20px;
- line-height:20px;
- overflow:hidden;
- -webkit-box-shadow: inset 2px 2px 3px 0px #888;
- box-shadow: inset 2px 2px 3px 0px #888;
+ float:left;
+ width:140px;
+ margin-left: 10px;
+ -webkit-border-radius: 6px;
+ border-radius: 6px;
+ background-color:#C5C5C5;
+ border: none;
+ color:#333;
+ font-weight:400;
+ padding:0px 0px 0px 8px;
+ height:20px;
+ line-height:20px;
+ overflow:hidden;
+ -webkit-box-shadow: inset 2px 2px 3px 0px #888;
+ box-shadow: inset 2px 2px 3px 0px #888;
}
#session-controls input[type=text] {
- background-color:#c5c5c5;
- border:none;
- color:#666;
+ background-color:#c5c5c5;
+ border:none;
+ color:#666;
}
.avatar-tiny {
- float:left;
- padding:1px;
- width:24px;
- height:24px;
- background-color:#ed3618;
- -webkit-border-radius:12px;
- -moz-border-radius:12px;
- border-radius:12px;
+ float:left;
+ padding:1px;
+ width:24px;
+ height:24px;
+ background-color:#ed3618;
+ -webkit-border-radius:12px;
+ -moz-border-radius:12px;
+ border-radius:12px;
}
.ftue-background {
- background-image:url(../images/content/bkg_ftue.jpg);
- background-repeat:no-repeat;
- background-size:cover;
- min-height:475px;
- min-width:672px;
+ background-image:url(../images/content/bkg_ftue.jpg);
+ background-repeat:no-repeat;
+ background-size:cover;
+ min-height:475px;
+ min-width:672px;
}
table.generaltable {
@@ -350,3 +350,33 @@ ul.shortcuts {
white-space:normal;
}
+.smallbutton {
+ font-size:10px !important;
+ padding:2px 8px !important;
+}
+
+.whitespace {
+ white-space:normal;
+}
+
+.w0 {width:0% !important}
+.w5 {width:5% !important}
+.w10 {width:10% !important}
+.w15 {width:15% !important}
+.w20 {width:20% !important}
+.w25 {width:25% !important}
+.w30 {width:30% !important}
+.w35 {width:35% !important}
+.w40 {width:40% !important}
+.w45 {width:45% !important}
+.w50 {width:50% !important}
+.w55 {width:55% !important}
+.w60 {width:60% !important}
+.w65 {width:65% !important}
+.w70 {width:70% !important}
+.w75 {width:75% !important}
+.w80 {width:80% !important}
+.w85 {width:85% !important}
+.w90 {width:90% !important}
+.w95 {width:95% !important}
+.w100 {width:100% !important}
\ No newline at end of file
diff --git a/web/app/assets/stylesheets/client/profile.css.scss b/web/app/assets/stylesheets/client/profile.css.scss
index 594b4ff07..1c9bc1441 100644
--- a/web/app/assets/stylesheets/client/profile.css.scss
+++ b/web/app/assets/stylesheets/client/profile.css.scss
@@ -144,7 +144,7 @@
}
.profile-bands {
- width:215px;
+ width:100%;
min-height:90px;
background-color:#242323;
position:relative;
@@ -173,6 +173,15 @@
padding-right:5px;
}
+.profile-band-list-result {
+ width:100%;
+ min-height:85px;
+ background-color:#242323;
+ position:relative;
+ margin:10px 0px 10px 0px;
+ padding-bottom:5px;
+}
+
.profile-social-left {
float:left;
width:32%;
@@ -216,3 +225,15 @@
.profile-block-city {
font-size:12px;
}
+
+.profile-musicians {
+ margin-top:-3px;
+ font-size:11px;
+}
+
+.profile-musicians td {
+ border-right:none;
+ border-top:none;
+ padding:3px;
+ vertical-align:middle;
+}
\ No newline at end of file
diff --git a/web/app/controllers/api_bands_controller.rb b/web/app/controllers/api_bands_controller.rb
index b815208d0..baf88d43c 100644
--- a/web/app/controllers/api_bands_controller.rb
+++ b/web/app/controllers/api_bands_controller.rb
@@ -47,6 +47,23 @@ class ApiBandsController < ApiController
respond_with @band, responder: ApiResponder, :status => :ok
end
+ def musician_index
+ unless params[:id].blank?
+ @musicians = Band.musician_index(params[:id])
+
+ else
+ render :json => { :message => "Band ID is required." }, :status => 400
+ end
+ end
+
+ def musician_create
+ end
+
+ def musician_destroy
+ unless params[:id].blank? || params[:user_id].blank?
+ end
+ end
+
###################### FOLLOWERS ########################
def liker_index
# NOTE: liker_index.rabl template references the likers property
diff --git a/web/app/views/api_bands/musician_index.rabl b/web/app/views/api_bands/musician_index.rabl
new file mode 100644
index 000000000..57b723984
--- /dev/null
+++ b/web/app/views/api_bands/musician_index.rabl
@@ -0,0 +1,11 @@
+collection @musicians
+
+attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :band_like_count, :follower_count, :following_count, :band_following_count, :recording_count, :session_count, :biography
+
+node :instruments do |musician|
+ unless musician.instruments.nil? || musician.instruments.size == 0
+ child :musician_instruments => :instruments do
+ attributes :description, :proficiency_level, :priority, :instrument_id
+ end
+ end
+end
diff --git a/web/app/views/api_bands/show.rabl b/web/app/views/api_bands/show.rabl
index fc4b171d9..bcd2ed486 100644
--- a/web/app/views/api_bands/show.rabl
+++ b/web/app/views/api_bands/show.rabl
@@ -1,6 +1,6 @@
object @band
-attributes :id, :name, :city, :state, :country, :website, :biography, :photo_url, :logo_url, :liker_count, :follower_count, :recording_count, :session_count
+attributes :id, :name, :city, :state, :country, :location, :website, :biography, :photo_url, :logo_url, :liker_count, :follower_count, :recording_count, :session_count
unless @band.users.nil? || @band.users.size == 0
child :users => :musicians do
diff --git a/web/app/views/api_users/band_index.rabl b/web/app/views/api_users/band_index.rabl
index 6ac9c409c..fb7b3a748 100644
--- a/web/app/views/api_users/band_index.rabl
+++ b/web/app/views/api_users/band_index.rabl
@@ -1,7 +1,24 @@
collection @bands
# do not retrieve all child collections when showing a list of bands
-attributes :id, :name, :location, :photo_url, :logo_url
+attributes :id, :name, :city, :state, :country, :location, :website, :biography, :photo_url, :logo_url, :liker_count, :follower_count, :recording_count, :session_count
+
+node :musicians do |band|
+ unless band.users.nil? || band.users.size == 0
+ child :users => :musicians do
+ attributes :id, :first_name, :last_name, :name, :photo_url, :biography
+
+ # TODO: figure out how to omit empty arrays
+ node :instruments do |user|
+ unless user.instruments.nil? || user.instruments.size == 0
+ child :musician_instruments => :instruments do
+ attributes :instrument_id, :description, :proficiency_level, :priority
+ end
+ end
+ end
+ end
+ end
+end
node :genres do |band|
unless band.genres.nil? || band.genres.size == 0
diff --git a/web/app/views/api_users/index.rabl b/web/app/views/api_users/index.rabl
index 8f9bbf9a7..7d9b57db6 100644
--- a/web/app/views/api_users/index.rabl
+++ b/web/app/views/api_users/index.rabl
@@ -1,4 +1,4 @@
collection @users
# do not retrieve all child collections when showing a list of users
-attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url
\ No newline at end of file
+attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url, :biography
\ No newline at end of file
diff --git a/web/app/views/api_users/show.rabl b/web/app/views/api_users/show.rabl
index 99394b57b..9a35978ef 100644
--- a/web/app/views/api_users/show.rabl
+++ b/web/app/views/api_users/show.rabl
@@ -1,6 +1,7 @@
object @user
-attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :band_like_count, :follower_count, :following_count, :band_following_count, :recording_count, :session_count
+attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :band_like_count, :follower_count, :following_count, :band_following_count, :recording_count, :session_count,
+:biography
# give back more info if the user being fetched is yourself
if @user == current_user
diff --git a/web/app/views/clients/_bandProfile.html.erb b/web/app/views/clients/_bandProfile.html.erb
new file mode 100644
index 000000000..6228fd0a1
--- /dev/null
+++ b/web/app/views/clients/_bandProfile.html.erb
@@ -0,0 +1,106 @@
+
+