(function(context,$) { "use strict"; context.JK = context.JK || {}; context.JK.SessionList = function(app) { var EVENTS = context.JK.EVENTS; var gearUtils = context.JK.GearUtils; var sessionUtils = context.JK.SessionUtils; var helpBubble = context.JK.HelpBubbleHelper; 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 $latencyTemplate = $('#template-latency'); var $musicianTemplate = $('#template-musician-info'); var showJoinLink = true; var showRsvpLink = true; function renderActiveSession(session, tbGroup, myAudioLatency) { $('#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 = []; showJoinLink = session.musician_access; // render musicians who are already in the session if (session.active_music_session && "participants" in session.active_music_session && session.active_music_session.participants.length > 0) { 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]; } } // this provides a buffer at the top to shift the first latency tag down in the event there are NO in-session musicians else { latencyHtml += "
 
"; } // render users who have approved RSVPs if (session.approved_rsvps) { for (i=0; i < session.approved_rsvps.length; i++) { // do not show the user in this section if he is already in the session if ($.inArray(session.approved_rsvps[i].id, inSessionUsers) === -1) { if (session.approved_rsvps[i].id === context.JK.currentUserId) { showJoinLink = true; } var rsvpUserInfo = createRsvpUser(session.approved_rsvps[i], session); rsvpUsersHtml += rsvpUserInfo[0]; latencyHtml += rsvpUserInfo[1]; } else { showJoinLink = true; } } } // render if anyone interested if(session['is_unstructured_rsvp?']) { openSlotsHtml += sessionUtils.createOpenSlot($openSlotsTemplate, {description: 'Any Instrument'}) } // render open slots if (session.open_slots) { for (i=0; i < session.open_slots.length; i++) { openSlotsHtml += sessionUtils.createOpenSlot($openSlotsTemplate, session.open_slots[i]); } } // notation files if (session.music_notations) { for (i=0; i < session.music_notations.length; i++) { notationFileHtml += createNotationFile(session.music_notations[i]); } } 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)); var $offsetParent = $(tbGroup).closest('.content'); var $latencyBadge = $row.find('.latency-value'); var full_score = $latencyBadge.attr('data-full-score') || null; var internet_score = $latencyBadge.attr('data-internet-score') || null; var audio_latency = $latencyBadge.attr('data-audio-latency') || null; var latencyBadgeUserId = $latencyBadge.attr('data-user-id'); var scoreOptions = {offsetParent: $offsetParent}; helpBubble.scoreBreakdown($latencyBadge, context.JK.currentUserId == latencyBadgeUserId, full_score, myAudioLatency, audio_latency, internet_score, scoreOptions); $(tbGroup).append($row); if (showJoinLink) { // wire up the Join Link to the T&Cs dialog var $parentRow = $('tr[data-session-id=' + session.id + ']', tbGroup); $('.join-link', $parentRow).click(function(evt) { if(!context.JK.guardAgainstBrowser(app)) { return false; } if (!context.JK.JamServer.connected) { app.notifyAlert("Not Connected", 'To create or join a session, you must be connected to the server.'); return false; } gearUtils.guardAgainstInvalidConfiguration(app) .fail(function() { app.notify( { title: "Unable to Join Session", text: "You can only join a session once you have working audio gear and a tested internet connection." }) }) .done(function(){ joinClick(session.id); }) return false; }); } } function renderInactiveSession(session, tbGroup, $rowToUpdate, myAudioLatency) { var openSlots = false; var hasInvitation = false; var approvedRsvpId = null; // if set, the user has an accepted RSVP var pendingRsvpId = null; // if set, the user has a pending RSVP var hasPendingOrDeclinedRsvp = false; var openRsvps = session.open_rsvps; $('#actionHeader', tbGroup).html('RSVP'); var i = 0; var rsvpUsersHtml = '', openSlotsHtml = '', latencyHtml = '', notationFileHtml = ''; context._.each(session.pending_rsvp_requests, function(pending_rsvp_request) { if(pending_rsvp_request.user_id === context.JK.currentUserId) { pendingRsvpId = pending_rsvp_request.id; } }); // render users who have approved RSVPs if (session.approved_rsvps && session.approved_rsvps.length > 0) { context._.each(session.approved_rsvps, function(approved_rsvp) { if (approved_rsvp.id === context.JK.currentUserId) { approvedRsvpId = approved_rsvp.rsvp_request_id; } var rsvpUserInfo = createRsvpUser(approved_rsvp, session); rsvpUsersHtml += rsvpUserInfo[0]; latencyHtml += rsvpUserInfo[1]; }); } // this provides a buffer at the top to shift the first latency tag down in the event there are NO RSVP musicians else { latencyHtml += "
 
"; } if(session['is_unstructured_rsvp?']) { openSlots = true; // unstructured RSVP means there are always open slots openSlotsHtml += sessionUtils.createOpenSlot($openSlotsTemplate, {description: 'Any Instrument'}) } // render open slots if (session.open_slots) { for (i=0; i < session.open_slots.length; i++) { openSlots = true; openSlotsHtml += sessionUtils.createOpenSlot($openSlotsTemplate, session.open_slots[i]); } } // render pending invitations if (session.pending_invitations) { for (i=0; i < session.pending_invitations.length; i++) { if (session.pending_invitations[i].id === context.JK.currentUserId) { hasInvitation = true; } } } // notation files if (session.music_notations) { for (i=0; i < session.music_notations.length; i++) { notationFileHtml += createNotationFile(session.music_notations[i]); } } var sessionVals = buildSessionObject(session, notationFileHtml, rsvpUsersHtml, openSlotsHtml, latencyHtml); sessionVals.scheduled_start = session.pretty_scheduled_start_with_timezone; var $row = $(context.JK.fillTemplate($inactiveSessionTemplate.html(), sessionVals)); var $offsetParent = $(tbGroup).closest('.content'); var $latencyBadge = $row.find('.latency-value'); var full_score = $latencyBadge.attr('data-full-score') || null; var internet_score = $latencyBadge.attr('data-internet-score') || null; var audio_latency = $latencyBadge.attr('data-audio-latency') || null; var latencyBadgeUserId = $latencyBadge.attr('data-user-id'); var scoreOptions = {offsetParent: $offsetParent}; helpBubble.scoreBreakdown($latencyBadge, context.JK.currentUserId == latencyBadgeUserId, full_score, myAudioLatency, audio_latency, internet_score, scoreOptions); // initial page load if (!$rowToUpdate) { $(tbGroup).append($row); } // inline update after an RSVP submission / cancellation else { $rowToUpdate.replaceWith($row); } var $parentRow = $('tr[data-session-id=' + session.id + ']', tbGroup); var showRsvpLink = true; var noLinkText = ''; if (approvedRsvpId) { showRsvpLink = false; noLinkText = $('You have been confirmed for this session. Cancel'); noLinkText.find('a').click(function() { ui.launchRsvpCancelDialog(session.id, approvedRsvpId) .one(EVENTS.RSVP_CANCELED, function() { rest.getSessionHistory(session.id) .done(function(response) { renderInactiveSession(response, tbGroup, $parentRow, myAudioLatency); }); }) .one(EVENTS.DIALOG_CLOSED, function() { $(this).unbind(EVENTS.RSVP_CANCELED); }); return false; }); } else if (pendingRsvpId) { showRsvpLink = false; noLinkText = $('You have RSVP\'ed to this session. Cancel'); noLinkText.find('a').click(function() { ui.launchRsvpCancelDialog(session.id, pendingRsvpId) .one(EVENTS.RSVP_CANCELED, function() { rest.getSessionHistory(session.id) .done(function(response) { renderInactiveSession(response, tbGroup, $parentRow, myAudioLatency); }); }) .one(EVENTS.DIALOG_CLOSED, function() { $(this).unbind(EVENTS.RSVP_CANCELED); }); return false; }); } else if (!openSlots) { showRsvpLink = false; noLinkText = 'No more openings in this session.'; } else if (!openRsvps && !hasInvitation) { showRsvpLink = false; noLinkText = 'You need an invitation to RSVP to this session.'; } if (showRsvpLink) { $('.rsvp-msg', $parentRow).hide(); $('.rsvp-link', $parentRow).show(); $('.rsvp-link', $parentRow).click(function(evt) { ui.launchRsvpSubmitDialog(session.id) .one(EVENTS.RSVP_SUBMITTED, function() { rest.getSessionHistory(session.id) .done(function(response) { renderInactiveSession(response, tbGroup, $parentRow, myAudioLatency); }); }) .one(EVENTS.DIALOG_CLOSED, function() { $(this).unbind(EVENTS.RSVP_SUBMITTED); }); return false; }); } else { $('.rsvp-msg', $parentRow).html(noLinkText).show(); $('.rsvp-link', $parentRow).hide(); } } function buildSessionObject(session, notationFileHtml, rsvpUsersHtml, openSlotsHtml, latencyHtml) { return { id: session.id, 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 = context.JK.getInstrumentIcon24(track.instrument_id); 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._.template($latencyTemplate.html(), $.extend(sessionUtils.createLatency(participant.user), participant.user), { variable: 'data' }); 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 = context.JK.getInstrumentIcon24(instrument.id); 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._.template($latencyTemplate.html(), $.extend(sessionUtils.createLatency(user), user), { variable: 'data' }); return [musicianHtml, latencyHtml]; } function createNotationFile(notation) { var notationVals = { file_url: notation.file_url, file_name: notation.file_name }; return context.JK.fillTemplate($notationFileTemplate.html(), notationVals); } 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 rest.getSession(sessionId) .done(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 === JK.currentUserId) { hasInvitation = true; break; } } } if (session) { // if user has an invitation, always open terms and allow joining regardless of settings if (hasInvitation) { logger.debug("Found invitation for user " + JK.currentUserId + ", session " + sessionId); openTerms(sessionId); } else { if(session.user_id == JK.currentUserId) { openTerms(sessionId); } else if (session.musician_access) { if (session.approval_required) { openAlert(sessionId); } else { openTerms(sessionId); } } } } }) .fail(function(xhr, textStatus, errorMessage) { logger.debug("xhr.status = " + xhr.status); if (xhr.status === 404) { sessionNotJoinableAlert(); } else { JK.app.notify( { title: "Unable to Join Session", text: "There was an unexpected error while attempting to join the session." }, null, 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?", sessionId, onCreateJoinRequest); 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'); } ); alertDialog.initialize(); app.layout.showDialog('alert'); } function onCreateJoinRequest(sessionId) { var joinRequest = {}; joinRequest.music_session = sessionId; joinRequest.user = context.JK.currentUserId; rest.createJoinRequest(joinRequest) .done(function(response) { }).error(app.ajaxError); app.layout.closeDialog('alert'); } function openTerms(sessionId) { var termsDialog = new context.JK.TermsDialog(app, sessionId, onTermsAccepted); termsDialog.initialize(); app.layout.showDialog('terms'); } function onTermsAccepted(sessionId) { context.location = '/client#/session/' + sessionId; } this.renderActiveSession = renderActiveSession; this.renderInactiveSession = renderInactiveSession; return this; }})(window,jQuery);