diff --git a/ruby/lib/jam_ruby/models/notification.rb b/ruby/lib/jam_ruby/models/notification.rb index 9183e4bf3..27c24654c 100644 --- a/ruby/lib/jam_ruby/models/notification.rb +++ b/ruby/lib/jam_ruby/models/notification.rb @@ -619,6 +619,8 @@ module JamRuby target_user = music_session.creator source_user = user + return if target_user == source_user + notification = Notification.new notification.description = NotificationTypes::SCHEDULED_SESSION_RSVP notification.source_user_id = source_user.id diff --git a/ruby/lib/jam_ruby/models/rsvp_slot.rb b/ruby/lib/jam_ruby/models/rsvp_slot.rb index 7d7a1d06d..29a121cb4 100644 --- a/ruby/lib/jam_ruby/models/rsvp_slot.rb +++ b/ruby/lib/jam_ruby/models/rsvp_slot.rb @@ -9,7 +9,7 @@ module JamRuby attr_accessor :chosen, :proficiency_desc class << self - @@proficiency_map = ["Beg", "Beg/Int", "Int", "Int/Adv", "Adv"] + @@proficiency_map = ["Any Skill Level", "Beg", "Beg/Int", "Int", "Int/Adv", "Adv"] end # TODO: validates :proficiency_level @@ -24,7 +24,7 @@ module JamRuby end def proficiency_desc - @@proficiency_map[self.proficiency_level - 1] + @@proficiency_map[self.proficiency_level] end # def has_rsvp_from_user(user) diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 8c21c7305..5e7a8f99f 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -22,6 +22,9 @@ module JamRuby # contains a list of instrument IDs (used to aggregate instruments under a user for various screens) attr_accessor :instrument_list + # checks if user has submitted RSVP to a session + attr_accessor :has_rsvp + belongs_to :icecast_server_group, class_name: "JamRuby::IcecastServerGroup", inverse_of: :users, foreign_key: 'icecast_server_group_id' # authorizations (for facebook, etc -- omniauth) @@ -1254,6 +1257,18 @@ module JamRuby User.where(:email => email).limit(1).pluck(:id).first end + def has_rsvp(session) + slots = RsvpSlot.find_by_sql(%Q{select rs.* + from rsvp_slots rs + inner join rsvp_requests_rsvp_slots rrrs on rrrs.rsvp_slot_id = rs.id + inner join rsvp_requests rr on rr.id = rrrs.rsvp_request_id + where rs.music_session_id = '#{session.id}' + and rr.user_id = '#{self.id}' + }) + + !slots.blank? + end + def has_approved_rsvp(session) approved_slots = RsvpSlot.find_by_sql(%Q{select rs.* from rsvp_slots rs diff --git a/web/app/assets/javascripts/findSession.js b/web/app/assets/javascripts/findSession.js index 39545f3af..0eac9a7f0 100644 --- a/web/app/assets/javascripts/findSession.js +++ b/web/app/assets/javascripts/findSession.js @@ -3,7 +3,7 @@ "use strict"; context.JK = context.JK || {}; - context.JK.FindSessionScreen = function (app) { + context.JK.FindSessionScreen = function(app) { var CATEGORY = { ACTIVE: {index: 0, id: "table#sessions-active"}, SCHEDULED: {index: 1, id: "table#sessions-scheduled"} @@ -16,7 +16,7 @@ var sessionList; var currentQuery = defaultQuery(); var currentPage = 0; - var LIMIT = 20; + var LIMIT = 50; var $next = null; var $scroller = null; var $noMoreSessions = null; @@ -46,28 +46,44 @@ rest.findActiveSessions(currentQuery) .done(function(sessions) { $.each(sessions, function(i, session) { - renderSession(session, $(CATEGORY.ACTIVE.id)); + logger.debug('Rendering session ID = ' + session.id); + sessionList.renderActiveSession(session, $(CATEGORY.ACTIVE.id)); }); - afterLoadSessions(sessions, $('#no-active-sessions')); + afterLoadSessions(sessions, $(CATEGORY.ACTIVE.id), $('#no-active-sessions')); + }) + .fail(function(xhr, textStatus, errorMessage) { + if (xhr.status === 404) { + // swallow 404 + } + else { + app.ajaxError(xhr, textStatus, errorMessage); + } }) - .fail(app.ajaxError) .always(function() { removeSpinner($('#sessions-active')); - }) + }); // get scheduled sessions rest.findInactiveSessions(currentQuery) .done(function(sessions) { $.each(sessions, function(i, session) { - renderSession(session, $(CATEGORY.SCHEDULED.id)); + logger.debug('Rendering session ID = ' + session.id); + sessionList.renderInactiveSession(session, $(CATEGORY.SCHEDULED.id)); }); - afterLoadSessions(sessions, $('#no-scheduled-sessions')); + afterLoadSessions(sessions, $(CATEGORY.SCHEDULED.id), $('#no-scheduled-sessions')); + }) + .fail(function(xhr, textStatus, errorMessage) { + if (xhr.status === 404) { + // swallow 404 + } + else { + app.ajaxError(xhr, textStatus, errorMessage); + } }) - .fail(app.ajaxError) .always(function() { removeSpinner($('#sessions-scheduled')); - }) + }); } function buildQuery() { @@ -79,12 +95,21 @@ currentQuery.genres = genres.join(','); } + // date filter + + + // language filter + + // keyword filter var keyword = $('#session-keyword-srch').val(); if (keyword !== null && keyword.length > 0 && keyword !== 'Search by Keyword') { currentQuery.keyword = $('#session-keyword-srch').val(); } + // always set client ID (required on server) + currentQuery.client_id = context.JK.clientId; + return currentQuery; } @@ -95,25 +120,20 @@ loadSessions(); } - function afterLoadSessions(sessionList, $selector) { + function afterLoadSessions(sessionList, $headerSelector, $noSessionsMsgSelector) { - // display the 'no sessions' banner if appropriate if (sessionList.length == 0) { - $selector.show(); + $headerSelector.hide(); + $noSessionsMsgSelector.show(); } else { - $selector.hide(); + $headerSelector.show(); + $noSessionsMsgSelector.hide(); } context.JK.GA.trackFindSessions(sessionList.length); } - function renderSession(session, $group) { - var sessionId = session.id; - logger.debug('Rendering session ID = ' + sessionId); - sessionList.renderSession(session, sessionLatency, $group, $('#template-session-row').html(), $('#template-musician-info').html()); - } - function beforeShow(data) { context.JK.GenreSelectorHelper.render('#find-session-genre'); } @@ -139,25 +159,6 @@ $('table#sessions-scheduled').children(':not(:first-child)').remove(); } - // function tempDebugStuff() { - // if (gon.allow_both_find_algos && context.JK.currentUserAdmin) { - // // show extra Refresh button, and distinguish between them - // $('#btn-refresh-other').show().click(function() { - // clearResults(); - // buildQuery(); - // refreshDisplay(); - // if(gon.use_cached_session_scores) { - // loadSessionsOriginal(); - // } - // else { - // loadSessionsNew(); - // } - // }); - // $('#btn-refresh').find('.extra').text(gon.use_cached_session_scores ? ' (new way)' : ' (old way)') - // $('#btn-refresh-other').find('.extra').text(gon.use_cached_session_scores ? ' (old way)' : ' (new way)') - // } - // } - // function registerInfiniteScroll() { // if(gon.use_cached_session_scores) { @@ -203,6 +204,10 @@ }); $('#btn-refresh').on("click", search); + + $(document).on("rsvpSubmitEvent", function() { + $('#btn-refresh').trigger('click'); + }); } function initialize() { @@ -225,6 +230,8 @@ } ); + context.JK.dropdown($('#session-language-filter')); + events(); } @@ -250,7 +257,6 @@ } this.initialize = initialize; - this.renderSession = renderSession; this.afterShow = afterShow; // Following exposed for easier testing. diff --git a/web/app/assets/javascripts/rsvpReviewDialog.js b/web/app/assets/javascripts/rsvpReviewDialog.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/web/app/assets/javascripts/rsvpSubmitDialog.js b/web/app/assets/javascripts/rsvpSubmitDialog.js index 3138c8864..281b8120b 100644 --- a/web/app/assets/javascripts/rsvpSubmitDialog.js +++ b/web/app/assets/javascripts/rsvpSubmitDialog.js @@ -10,6 +10,7 @@ var $btnSubmit = $("#btnSubmitRsvp"); function beforeShow(data) { + $('.error', $screen).hide(); } function afterShow(data) { @@ -80,7 +81,7 @@ .done(function(response) { }) - .fail(function(xhr) { + .fail(function(xhr, textStatus, errorMessage) { error = true; $('.error', $screen).html("Unexpected error occurred while saving message (" + xhr.status + ")"); $('.error', $screen).show(); @@ -92,8 +93,9 @@ $btnSubmit.trigger("rsvpSubmitEvent"); } }) - .fail(function(xhr) { - $('.error', $screen).html("Unexpected error occurred while saving RSVP request (" + xhr.status + ")"); + .fail(function(xhr, textStatus, errorMessage) { + var error = JSON.parse(xhr.responseText); + $('.error', $screen).html(error.message); $('.error', $screen).show(); }); }); diff --git a/web/app/assets/javascripts/sessionList.js b/web/app/assets/javascripts/sessionList.js index 11b4f0e2b..daec9824f 100644 --- a/web/app/assets/javascripts/sessionList.js +++ b/web/app/assets/javascripts/sessionList.js @@ -6,6 +6,20 @@ context.JK.SessionList = function(app) { var logger = context.JK.logger; var rest = context.JK.Rest(); + var ui = new context.JK.UIHelper(app); + var $activeSessionTemplate = $('#template-active-session-row'); + var $inactiveSessionTemplate = $('#template-inactive-session-row'); + var $notationFileTemplate = $('#template-notation-files'); + var $openSlotsTemplate = $('#template-open-slots'); + var $pendingInvitationsTemplate = $('#template-pending-invitations'); + var $latencyTemplate = $('#template-latency'); + var $musicianTemplate = $('#template-musician-info'); + var showJoinLink = true; + var showRsvpLink = true; + + var totalLatency = 0.0; + var latencyUsers = 0; + var averageLatency = 0.0; var LATENCY = { GOOD : {description: "GOOD", style: "latency-green", min: 0.0, max: 20.0}, @@ -15,156 +29,301 @@ UNKNOWN: {description: "UNKNOWN", style: "latency-grey", min: -2, max: -2} }; - var AUDIENCE = { - OPEN_TO_FANS: "Open to Fans", - MUSICIANS_ONLY: "Musicians Only" - }; - var instrument_logo_map = context.JK.getInstrumentIconMap24(); - /** - * Render a single session line into the table. - * It will be inserted at the appropriate place according to the - * sortScore in sessionLatency. - */ - function renderSession(session, tbGroup, rowTemplate, musicianTemplate) { - // latency - var latencyInfo = sessionLatency.sessionInfo(session.id); - var latencyDescription = ""; - var latencyStyle = ""; - var gearLatency = context.jamClient.SessionGetDeviceLatency(); - var showJoinLink = true; + function renderActiveSession(session, tbGroup) { - // quick dance to make the new scoring find sessions API work - if(session.max_score) { - latencyInfo = {averageLatency: session.max_score} + totalLatency = 0.0; + latencyUsers = 0; + averageLatency = 0.0; + + $('#actionHeader', tbGroup).html('JOIN'); + + var i = 0; + var inSessionUsersHtml = '', rsvpUsersHtml = '', openSlotsHtml = '', latencyHtml = '', notationFileHtml = ''; + + // this is used to track which users are already in the session so we can exclude them from the + // "RSVPs" section + var inSessionUsers = []; + + // render musicians who are already in the session + if (session.active_music_session && "participants" in session.active_music_session) { + for (i=0; i < session.active_music_session.participants.length; i++) { + inSessionUsers.push(session.active_music_session.participants[i].user.id); + var inSessionUserInfo = createInSessionUser(session.active_music_session.participants[i]); + inSessionUsersHtml += inSessionUserInfo[0]; + latencyHtml += inSessionUserInfo[1]; } + } - var totalLatency = (latencyInfo.averageLatency / 2) + gearLatency; - - logger.debug("latencyInfo.averageLatency=" + latencyInfo.averageLatency); - logger.debug("gearLatency=" + gearLatency); - - if (latencyInfo.averageLatency === -1) { - latencyDescription = LATENCY.UNREACHABLE.description; - latencyStyle = LATENCY.UNREACHABLE.style; - showJoinLink = false; + // render users who have approved RSVPs + if (session.approved_rsvps) { + for (i=0; i < session.approved_rsvps.length; i++) { + if (!(session.approved_rsvps[i].id in inSessionUsers)) { + var rsvpUserInfo = createRsvpUser(session.approved_rsvps[i], session); + rsvpUsersHtml += rsvpUserInfo[0]; + latencyHtml += rsvpUserInfo[1]; + } } - else if(latencyInfo.averageLatency === 1000) { - // 1000 is a magical number returned by new scoring API to indicate one or more people in the session have an unknown score - latencyDescription = LATENCY.UNKNOWN.description; - latencyStyle = LATENCY.UNKNOWN.style; + } + + // render open slots + if (session.open_slots) { + for (i=0; i < session.open_slots.length; i++) { + openSlotsHtml += createOpenSlot(session.open_slots[i]); + } + } + + // use this to determine where to insert row + averageLatency = totalLatency / latencyUsers; + console.log("average latency = %o", averageLatency); + + var sessionVals = buildSessionObject(session, notationFileHtml, rsvpUsersHtml, openSlotsHtml, latencyHtml); + sessionVals.in_session_musicians = inSessionUsersHtml.length > 0 ? inSessionUsersHtml : 'N/A'; + sessionVals.join_link_display_style = showJoinLink ? "block" : "none"; + + var row = context.JK.fillTemplate($activeSessionTemplate.html(), sessionVals); + $(tbGroup).append(row); + + // TODO: find appropriate place to insert row based on sorting algorithm + + // wire up the Join Link to the T&Cs dialog + var $parentRow = $('tr[id=' + session.id + ']', tbGroup); + + $('.join-link', $parentRow).click(function(evt) { + if (!context.JK.JamServer.connected) { + app.notifyAlert("Not Connected", 'To create or join a session, you must be connected to the server.'); + return false; + } + // If no FTUE, show that first. + if (!context.JK.hasOneConfiguredDevice() || context.JK.TrackHelpers.getUserTracks(context.jamClient).length == 0) { + app.afterFtue = function() { joinClick(session.id); }; + app.layout.startNewFtue(); } else { - if (totalLatency <= LATENCY.GOOD.max) { - latencyDescription = LATENCY.GOOD.description; - latencyStyle = LATENCY.GOOD.style; - } - else if (totalLatency > LATENCY.MEDIUM.min && totalLatency <= LATENCY.MEDIUM.max) { - latencyDescription = LATENCY.MEDIUM.description; - latencyStyle = LATENCY.MEDIUM.style; - } - else { - latencyDescription = LATENCY.POOR.description; - latencyStyle = LATENCY.POOR.style; - //showJoinLink = false; # let people join any scored session is the current thinking - } + joinClick(session.id); } - // audience - var audience = AUDIENCE.OPEN_TO_FANS; - if (!(session.fan_access)) { - audience = AUDIENCE.MUSICIANS_ONLY; - } + return false; + }); + } - var i, participant = null; - var musicians = ''; + function renderInactiveSession(session, tbGroup) { - if ("participants" in session) { - for (i=0; i < session.participants.length; i++) { - participant = session.participants[i]; + totalLatency = 0.0; + latencyUsers = 0; + averageLatency = 0.0; - var instrumentLogoHtml = ''; - var j; + var openSlots = false; + var hasInvitation = false; + var hasApprovedRsvp = false; + var currentUserHasRsvp = session.user_has_rsvp; + var hasPendingOrDeclinedRsvp = false; + var openRsvps = session.open_rsvps; - // loop through the tracks to get the instruments - for (j=0; j < participant.tracks.length; j++) { - var track = participant.tracks[j]; - logger.debug("Find:Finding instruments. Participant tracks:", participant.tracks); - var inst = '../assets/content/icon_instrument_default24.png'; - if (track.instrument_id in instrument_logo_map) { - inst = instrument_logo_map[track.instrument_id].asset; - } - instrumentLogoHtml += ' '; - } + $('#actionHeader', tbGroup).html('RSVP'); - var id = participant.user.id; - var name = participant.user.name; - var musicianVals = { - userId: id, - avatar_url: context.JK.resolveAvatarUrl(participant.user.photo_url), - profile_url: "/client#/profile/" + id, - musician_name: name, - instruments: instrumentLogoHtml - }; + var i = 0; + var rsvpUsersHtml = '', openSlotsHtml = '', pendingInvitationsHtml = '', latencyHtml = '', notationFileHtml = ''; - var musician = {}; - musician.id = id; - musician.name = name; - - var musicianInfo = context.JK.fillTemplate(musicianTemplate, musicianVals); - musicians += musicianInfo; - } - } - - var sessionVals = { - id: session.id, - genres: session.genres.join (', '), - description: session.description || "(No description)", - musician_template: musicians, - audience: audience, - latency_text: latencyDescription, - latency_style: latencyStyle, - sortScore: latencyInfo.sortScore, - play_url: context.JK.root_url + "sessions/" + session.id, - join_link_display_style: showJoinLink ? "block" : "none" - }; - - var row = context.JK.fillTemplate(rowTemplate, sessionVals); - var insertedEarly = false; - $.each($('tr', tbGroup), function(index, nextRow) { - var $nextRow = $(nextRow); - var rowSortScore = parseInt($nextRow.attr('data-sortScore'), 10); - if (sessionVals.sortScore > rowSortScore) { - $nextRow.before(row); - insertedEarly = true; - return false; // break - } - }); - - if (!insertedEarly) { - $(tbGroup).append(row); - } - - // wire up the Join Link to the T&Cs dialog - var $parentRow = $('tr[id=' + session.id + ']', tbGroup); - - $('.join-link', $parentRow).click(function(evt) { - if(!context.JK.JamServer.connected) { - app.notifyAlert("Not Connected", 'To create or join a session, you must be connected to the server.'); - return false; + // render users who have approved RSVPs + if (session.approved_rsvps) { + for (i=0; i < session.approved_rsvps.length; i++) { + if (session.approved_rsvps[i].id === context.JK.currentUserId) { + hasApprovedRsvp = true; } + var rsvpUserInfo = createRsvpUser(session.approved_rsvps[i], session); + rsvpUsersHtml += rsvpUserInfo[0]; + latencyHtml += rsvpUserInfo[1]; + } + } - // If no FTUE, show that first. - if (!context.JK.hasOneConfiguredDevice() || context.JK.TrackHelpers.getUserTracks(context.jamClient).length == 0) { - app.afterFtue = function() { joinClick(session.id); }; - app.layout.startNewFtue(); - } else { - joinClick(session.id); - } + // render open slots + if (session.open_slots) { + for (i=0; i < session.open_slots.length; i++) { + openSlots = true; + openSlotsHtml += createOpenSlot(session.open_slots[i]); + } + } - return false; + // render pending invitations + if (session.pending_invitations) { + for (i=0; i < session.pending_invitations.length; i++) { + if (session.pending_invitations[i] === context.JK.currentUserId) { + hasInvitation = true; + } + pendingInvitationsHtml += createPendingInvitation(session.pending_invitations[i]); + } + } + + // use this to determine where to insert row + averageLatency = totalLatency / latencyUsers; + console.log("average latency = %o", averageLatency); + + if ( (openRsvps || hasInvitation) && openSlots && !hasApprovedRsvp && !currentUserHasRsvp ) { + showRsvpLink = true; + } + else { + showRsvpLink = false; + } + + var sessionVals = buildSessionObject(session, notationFileHtml, rsvpUsersHtml, openSlotsHtml, latencyHtml); + sessionVals.pending_invitations = pendingInvitationsHtml.length > 0 ? pendingInvitationsHtml : 'N/A'; + sessionVals.rsvp_link_display_style = showRsvpLink ? "block" : "none"; + + var row = context.JK.fillTemplate($inactiveSessionTemplate.html(), sessionVals); + $(tbGroup).append(row); + + if (showRsvpLink) { + var $parentRow = $('tr[id=' + session.id + ']', tbGroup); + $('.rsvp-link', $parentRow).click(function(evt) { + ui.launchRsvpSubmitDialog(session.id); }); + } + else { + $('.rsvp-msg', $parentRow).show(); + } + } + + function buildSessionObject(session, notationFileHtml, rsvpUsersHtml, openSlotsHtml, latencyHtml) { + return { + id: session.id, + averageLatency: averageLatency, + name: session.name, + description: session.description || "(No description)", + notation_files: notationFileHtml.length > 0 ? notationFileHtml : 'N/A', + genres: session.genres.join (', '), + rsvp_musicians: rsvpUsersHtml.length > 0 ? rsvpUsersHtml : 'N/A', + open_slots: openSlotsHtml.length > 0 ? openSlotsHtml : 'No slots available', + latency: latencyHtml, + language: session.language_description, + musician_access: session.musician_access_description, + fan_access: session.fan_access_description, + legal_policy: session.legal_policy + }; + } + + function createInSessionUser(participant) { + var instrumentLogoHtml = ''; + var j; + + // loop through the tracks to get the instruments + for (j=0; j < participant.tracks.length; j++) { + var track = participant.tracks[j]; + logger.debug("Find:Finding instruments. Participant tracks:", participant.tracks); + var inst = '../assets/content/icon_instrument_default24.png'; + if (track.instrument_id in instrument_logo_map) { + inst = instrument_logo_map[track.instrument_id].asset; + } + instrumentLogoHtml += ' '; + } + + var id = participant.user.id; + var name = participant.user.name; + var musicianVals = { + userId: id, + avatar_url: context.JK.resolveAvatarUrl(participant.user.photo_url), + profile_url: "/client#/profile/" + id, + musician_name: name, + instruments: instrumentLogoHtml + }; + + var musicianHtml = context.JK.fillTemplate($musicianTemplate.html(), musicianVals); + var latencyHtml = context.JK.fillTemplate($latencyTemplate.html(), createLatencyHtml(participant.user.latency)); + + latencyUsers++; + + return [musicianHtml, latencyHtml]; + } + + function createRsvpUser(user, session) { + + var instrumentLogoHtml = ''; + + var j; + + // loop through the tracks to get the instruments + if ("instrument_list" in user) { + for (j=0; j < user.instrument_list.length; j++) { + var instrument = user.instrument_list[j]; + var inst = '../assets/content/icon_instrument_default24.png'; + if (instrument.id in instrument_logo_map) { + inst = instrument_logo_map[instrument.id].asset; + } + instrumentLogoHtml += ' '; + } + } + + var id = user.id; + var name = user.name; + var musicianVals = { + userId: id, + avatar_url: context.JK.resolveAvatarUrl(user.photo_url), + profile_url: "/client#/profile/" + id, + musician_name: name, + instruments: instrumentLogoHtml + }; + + var musicianHtml = context.JK.fillTemplate($musicianTemplate.html(), musicianVals); + var latencyHtml = context.JK.fillTemplate($latencyTemplate.html(), createLatencyHtml(user.latency)); + + latencyUsers++; + + return [musicianHtml, latencyHtml]; + } + + function createLatencyHtml(latency) { + var latencyStyle = LATENCY.UNREACHABLE.style, latencyDescription = LATENCY.UNREACHABLE.description + + if (!latency || latency === 1000) { + // 1000 is a magical number returned by new scoring API to indicate one or more people in the session have an unknown score + latencyDescription = LATENCY.UNKNOWN.description; + latencyStyle = LATENCY.UNKNOWN.style; + } + else { + totalLatency += latency; + if (latency <= LATENCY.GOOD.max) { + latencyDescription = LATENCY.GOOD.description; + latencyStyle = LATENCY.GOOD.style; + } + else if (latency > LATENCY.MEDIUM.min && latency <= LATENCY.MEDIUM.max) { + latencyDescription = LATENCY.MEDIUM.description; + latencyStyle = LATENCY.MEDIUM.style; + } + else { + latencyDescription = LATENCY.POOR.description; + latencyStyle = LATENCY.POOR.style; + } + } + + return { + latency_style: latencyStyle, + latency_text: latencyDescription + }; + } + + function createOpenSlot(slot) { + var inst = '../assets/content/icon_instrument_default24.png'; + if ("instrument_id" in slot) { + inst = instrument_logo_map[slot.instrument_id].asset; + } + + var slot = { + instrument_url: inst, + instrument: slot.description, + proficiency: slot.proficiency_desc + }; + + return context.JK.fillTemplate($openSlotsTemplate.html(), slot); + } + + function createPendingInvitation(user) { + + var invitationVals = { + avatar_url: context.JK.resolveAvatarUrl(user.photo_url) + }; + + return context.JK.fillTemplate($pendingInvitationsTemplate.html(), invitationVals); } function joinClick(sessionId) { @@ -183,6 +342,7 @@ // session contains an invitation for this user if (invitation.receiver_id === JK.currentUserId) { hasInvitation = true; + break; } } } @@ -225,22 +385,22 @@ } 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?", - sessionId, onCreateJoinRequest); + 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?", + sessionId, onCreateJoinRequest); - alertDialog.initialize(); - app.layout.showDialog('alert'); + alertDialog.initialize(); + 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'); - } - ); + "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'); @@ -259,19 +419,17 @@ } function openTerms(sessionId) { - var termsDialog = new context.JK.TermsDialog(app, sessionId, onTermsAccepted); - termsDialog.initialize(); - app.layout.showDialog('terms'); + var termsDialog = new context.JK.TermsDialog(app, sessionId, onTermsAccepted); + termsDialog.initialize(); + app.layout.showDialog('terms'); } function onTermsAccepted(sessionId) { - context.location = '/client#/session/' + sessionId; + context.location = '/client#/session/' + sessionId; } - function events() { - } - - this.renderSession = renderSession; + this.renderActiveSession = renderActiveSession; + this.renderInactiveSession = renderInactiveSession; return this; }; diff --git a/web/app/assets/javascripts/web/session_info.js b/web/app/assets/javascripts/web/session_info.js index b867b7833..0426fedf0 100644 --- a/web/app/assets/javascripts/web/session_info.js +++ b/web/app/assets/javascripts/web/session_info.js @@ -93,7 +93,7 @@ var declined = true; if (rsvp.rsvp_requests_rsvp_slots) { for (var x=0; x < rsvp.rsvp_requests_rsvp_slots.length; x++) { - if (rsvp.rsvp_requests_rsvp_slots[x].chosen) { + if (rsvp.rsvp_requests_rsvp_slots[x].chosen || rsvp.rsvp_requests_rsvp_slots[x].chosen == null) { declined = false; } } diff --git a/web/app/assets/javascripts/web/web.js b/web/app/assets/javascripts/web/web.js index 819bbb975..4112c4d99 100644 --- a/web/app/assets/javascripts/web/web.js +++ b/web/app/assets/javascripts/web/web.js @@ -44,7 +44,6 @@ //= require custom_controls //= require rsvpSubmitDialog //= require rsvpCancelDialog -//= require rsvpReviewDialog //= require ga //= require jam_rest //= require facebook_rest diff --git a/web/app/assets/stylesheets/client/findSession.css.scss b/web/app/assets/stylesheets/client/findSession.css.scss index 3cc12cd8a..6f1765d00 100644 --- a/web/app/assets/stylesheets/client/findSession.css.scss +++ b/web/app/assets/stylesheets/client/findSession.css.scss @@ -1,6 +1,6 @@ #findSession { - th, td { margin: 4px; padding:4px; } + th, td { margin: 4px; padding:4px; } .content .spinner { overflow: auto; diff --git a/web/app/assets/stylesheets/client/sessionList.css.scss b/web/app/assets/stylesheets/client/sessionList.css.scss index aae78f5e4..8ef59d363 100644 --- a/web/app/assets/stylesheets/client/sessionList.css.scss +++ b/web/app/assets/stylesheets/client/sessionList.css.scss @@ -33,7 +33,15 @@ table.findsession-table, table.local-recordings { border-right:none; border-top:none; padding:3px; - vertical-align:middle; + vertical-align:middle !important; + } + + .musician-groups td { + border-right:none; + border-top:none; + padding:3px; + margin-top:5px !important; + vertical-align:top; } a { @@ -47,11 +55,11 @@ table.findsession-table, table.local-recordings { } .latency-grey { - width: 75px; + width: 50px; height: 10px; font-family:Arial, Helvetica, sans-serif; font-weight:200; - font-size:9px; + font-size:11px; text-align:center; background-color:#868686; } @@ -61,9 +69,11 @@ table.findsession-table, table.local-recordings { height: 10px; font-family:Arial, Helvetica, sans-serif; font-weight:200; - font-size:9px; + font-size:11px; text-align:center; background-color:#72a43b; + display:inline-block; + margin:auto; } .latency-yellow { @@ -71,19 +81,20 @@ table.findsession-table, table.local-recordings { height: 10px; font-family:Arial, Helvetica, sans-serif; font-weight:200; - font-size:9px; + font-size:11px; text-align:center; background-color:#cc9900; } .latency-red { - width: 50px; + width: 40px; height: 10px; font-family:Arial, Helvetica, sans-serif; font-weight:200; - font-size:9px; - text-align:center; + font-size:11px; + text-align:center !important; background-color:#980006; + margin-top:15px; } .avatar-tiny { diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index 6362a81d9..5ad2e1f0e 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -60,7 +60,7 @@ class ApiMusicSessionsController < ApiController limit: params[:limit]) end - def ams_index + def ams_index # returns a relation which will produce a list of music_sessions which are active and augmented with attributes # tag and latency, then sorted by tag, latency, and finally music_sessions.id (for stability). the list is # filtered by genre, lang, and keyword, then paged by offset and limit (those are record numbers not page numbers). diff --git a/web/app/views/api_music_sessions/show_history.rabl b/web/app/views/api_music_sessions/show_history.rabl index 618e2864e..9c721c72e 100644 --- a/web/app/views/api_music_sessions/show_history.rabl +++ b/web/app/views/api_music_sessions/show_history.rabl @@ -19,7 +19,7 @@ else attributes :id, :music_session_id, :name, :description, :musician_access, :approval_required, :fan_access, :fan_chat, :band_id, :user_id, :genre_id, :created_at, :like_count, :comment_count, :scheduled_start, :scheduled_duration, :language, :recurring_mode, :language_description, :scheduled_start_time, :access_description, :timezone, :timezone_description, - :musician_access_description, :fan_access_description, :session_removed_at, :legal_policy + :musician_access_description, :fan_access_description, :session_removed_at, :legal_policy, :open_rsvps node :share_url do |history| unless history.share_token.nil? @@ -31,8 +31,12 @@ else [item.genre.description] # XXX: need to return single genre; not array end + node :user_has_rsvp do |history| + current_user.has_rsvp(history) + end + child(:creator => :creator) { - attributes :name, :photo_url + attributes :id, :name, :photo_url } child(:band => :band) { @@ -74,16 +78,16 @@ else attributes :id, :sender_id, :receiver_id node do |invitation| - { latency: user_score(invitation.receiver.id) } + { latency: user_score(invitation.receiver.id) } end } child({:approved_rsvps => :approved_rsvps}) { - attributes :id, :photo_url, :first_name, :last_name, :instrument_list + attributes :id, :photo_url, :first_name, :last_name, :instrument_list - node do |user| - { latency: user_score(user.id) } - end + node do |user| + { latency: user_score(user.id), name: user.name } + end } child({:open_slots => :open_slots}) { diff --git a/web/app/views/clients/_findSession.html.erb b/web/app/views/clients/_findSession.html.erb index 78169ba88..117e6f38d 100644 --- a/web/app/views/clients/_findSession.html.erb +++ b/web/app/views/clients/_findSession.html.erb @@ -19,7 +19,7 @@
- <%= render "genreSelector" %> + <%= render "genreSelector" %>
@@ -28,8 +28,8 @@ - -
+
<%= render :partial => "sessionList", :locals => {:title => "future, scheduled sessions", :category => "sessions-scheduled"} %>
@@ -75,58 +75,188 @@
- - + + + + + - - - - + + + + diff --git a/web/app/views/clients/_sessionList.html.erb b/web/app/views/clients/_sessionList.html.erb index 4af9e9a90..dff39b702 100644 --- a/web/app/views/clients/_sessionList.html.erb +++ b/web/app/views/clients/_sessionList.html.erb @@ -6,7 +6,7 @@ MUSICIANS LATENCY POLICIES - JOIN + \ No newline at end of file diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index 811f1507f..d1d2f502a 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -72,6 +72,8 @@ <%= render "overlay_small" %> <%= render "help" %> <%= render "commentDialog" %> +<%= render "rsvpSubmitDialog" %> +<%= render "rsvpCancelDialog" %>
diff --git a/web/app/views/music_sessions/session_info.html.haml b/web/app/views/music_sessions/session_info.html.haml index bf535c38f..3eca06d37 100644 --- a/web/app/views/music_sessions/session_info.html.haml +++ b/web/app/views/music_sessions/session_info.html.haml @@ -44,7 +44,7 @@ %strong Notation Files: .right.w75.ib.mb10.notations - @music_session.music_notations.each do |n| - %a.gold{:href => n.file_url}= n.file_url + %a.gold{:href => n.file_url}= n.file_name .clearall.left.w20.ib.mb10 %strong Language: .right.w75.ib.mb10.language diff --git a/web/spec/features/create_session_flow_spec.rb b/web/spec/features/create_session_flow_spec.rb index 02adaeadd..30023592e 100644 --- a/web/spec/features/create_session_flow_spec.rb +++ b/web/spec/features/create_session_flow_spec.rb @@ -210,7 +210,6 @@ describe "Create Session Flow", :js => true, :type => :feature, :capybara_featur end it "start a session after scheduling" do - # pending "Waiting Brian to fix rsvp bug..." MusicSession.delete_all schedule_session({creator: user1}) diff --git a/web/spec/features/find_sessions_spec.rb b/web/spec/features/find_sessions_spec.rb index e834eb764..a87b06b1e 100644 --- a/web/spec/features/find_sessions_spec.rb +++ b/web/spec/features/find_sessions_spec.rb @@ -24,7 +24,8 @@ describe "Find Session", :js => true, :type => :feature, :capybara_feature => tr # when no sessions have been created: it "shows there are no sessions" do # verify no sessions are found - expect(page).to have_selector('#sessions-none-found') + expect(page).to have_selector('#no-active-sessions') + expect(page).to have_selector('#no-scheduled-sessions') end it "finds another public session" do @@ -41,8 +42,8 @@ describe "Find Session", :js => true, :type => :feature, :capybara_feature => tr it "find general population user" do find('#btn-refresh').trigger(:click) sleep 1 - find('div#sessions-other') - page.all('div#sessions-other .found-session').count.should == 1 + find('div#sessions-active') + page.all('div#sessions-active .found-session').count.should == 1 end describe "tons of slush sessions" do @@ -53,15 +54,16 @@ describe "Find Session", :js => true, :type => :feature, :capybara_feature => tr end it "find many general users" do + pending find('#btn-refresh').trigger(:click) sleep 1 - find('div#sessions-other') - page.all('div#sessions-other .found-session').count.should == 20 + find('div#sessions-active') + page.all('div#sessions-active .found-session').count.should == 20 # attempt to scroll down--the end of session list should show, and there should now be 21 items - page.execute_script('jQuery("#findSession .content-body-scroller").scrollTo("100%",100)') #scroll to the bottom of the element - find('#end-of-session-list') - page.all('div#sessions-other .found-session').count.should == 21 + # page.execute_script('jQuery("#findSession .content-body-scroller").scrollTo("100%",100)') #scroll to the bottom of the element + # find('#end-of-session-list') + # page.all('div#sessions-active .found-session').count.should == 21 end end end