VRFS-2311 allow session creator to add and approve slots on the fly when there are no available slots
This commit is contained in:
parent
bcfc2def9e
commit
c57ea372ac
|
|
@ -27,6 +27,7 @@ require "jam_ruby/constants/validation_messages"
|
|||
require "jam_ruby/errors/permission_error"
|
||||
require "jam_ruby/errors/state_error"
|
||||
require "jam_ruby/errors/jam_argument_error"
|
||||
require "jam_ruby/errors/conflict_error"
|
||||
require "jam_ruby/lib/app_config"
|
||||
require "jam_ruby/lib/s3_manager_mixin"
|
||||
require "jam_ruby/lib/module_overrides"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
module JamRuby
|
||||
class ConflictError < Exception
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -724,7 +724,7 @@ module JamRuby
|
|||
|
||||
query = query.offset(offset)
|
||||
query = query.limit(limit)
|
||||
query = query.where("music_sessions.create_type IS NULL OR music_sessions.create_type != ?", MusicSession::CREATE_TYPE_QUICK_START)
|
||||
query = query.where("music_sessions.create_type IS NULL OR (music_sessions.create_type != ? AND music_sessions.create_type != ?)", MusicSession::CREATE_TYPE_QUICK_START, MusicSession::CREATE_TYPE_IMMEDIATE)
|
||||
query = query.where("music_sessions.genre_id = ?", genre) unless genre.blank?
|
||||
query = query.where('music_sessions.language = ?', lang) unless lang.blank?
|
||||
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", ActiveRecord::Base.connection.quote(keyword) + ':*') unless keyword.blank?
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ module JamRuby
|
|||
|
||||
# authorize the user attempting to respond to the RSVP request
|
||||
if music_session.creator.id != user.id
|
||||
raise PermissionError, "Only the session organizer can accept or decline and RSVP request."
|
||||
raise PermissionError, "Only the session organizer can accept or decline an RSVP request."
|
||||
end
|
||||
|
||||
rsvp_request = RsvpRequest.find_by_id(rsvp_request_id)
|
||||
|
|
@ -181,8 +181,35 @@ module JamRuby
|
|||
raise StateError, "Slot does not exist"
|
||||
end
|
||||
|
||||
# slot has already been accepted
|
||||
if rsvp_slot.chosen && r[:accept]
|
||||
raise StateError, "All RSVP slots for the #{rsvp_slot.instrument_id} have been already approved."
|
||||
# get the instrument and skill level for this slot and see if there are others available
|
||||
# and auto-reassign the request_slot to the open rsvp_slot
|
||||
open_slots = music_session.open_slots
|
||||
|
||||
# don't worry about matching proficiency if the user RSVPed to "Any Skill Level"
|
||||
if rsvp_slot.proficiency_level == 0
|
||||
open_slots = open_slots.select { |slot| slot.instrument_id == rsvp_slot.instrument_id }
|
||||
else
|
||||
open_slots = open_slots.select { |slot| slot.instrument_id == rsvp_slot.instrument_id && slot.proficiency_level == rsvp_slot.proficiency_level }
|
||||
end
|
||||
|
||||
# (1) another available slot exists matching this instrument and proficiency
|
||||
unless open_slots.blank?
|
||||
rsvp_slot = open_slots.first
|
||||
request_slot.rsvp_slot_id = rsvp_slot.id # this links the RsvpRequestRsvpSlot to the available open slot matching this instrument and proficiency level
|
||||
|
||||
# (2) no identical slots available => create a new one on the fly
|
||||
else
|
||||
new_slot = RsvpSlot.new
|
||||
new_slot.instrument_id = rsvp_slot.instrument_id
|
||||
new_slot.proficiency_level = rsvp_slot.proficiency_level
|
||||
new_slot.music_session_id = rsvp_slot.music_session_id
|
||||
new_slot.is_unstructured_rsvp = rsvp_slot.is_unstructured_rsvp
|
||||
new_slot.save!
|
||||
|
||||
request_slot.rsvp_slot_id = new_slot.id # saved below on line 218
|
||||
end
|
||||
end
|
||||
|
||||
if r[:accept]
|
||||
|
|
|
|||
|
|
@ -228,7 +228,47 @@ describe RsvpRequest do
|
|||
n.description.should == NotificationTypes::SCHEDULED_SESSION_RSVP_APPROVED
|
||||
end
|
||||
|
||||
it "should not allow approval of RSVP for a slot that has already been approved" do
|
||||
it "should allow approval of multiple RSVPs to same slot ID when multiple slots exist for same instrument and proficiency level" do
|
||||
@music_session.open_rsvps = true
|
||||
@music_session.save!
|
||||
|
||||
@slot2.delete
|
||||
|
||||
slot2 = FactoryGirl.build(:rsvp_slot, :music_session => @music_session, :instrument => JamRuby::Instrument.find('electric guitar'))
|
||||
slot2.save!
|
||||
|
||||
rsvp1 = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id], :message => "Let's Jam!"}, @session_invitee)
|
||||
rsvp2 = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id], :message => "Let's Jam!"}, @non_session_invitee)
|
||||
|
||||
rs1 = RsvpRequestRsvpSlot.find_by_rsvp_request_id(rsvp1.id)
|
||||
rs1.rsvp_slot_id.should == @slot1.id
|
||||
|
||||
# approve RSVP 1
|
||||
RsvpRequest.update({:id => rsvp1.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => true}]}, @session_creator)
|
||||
|
||||
# ensure slot ID didn't change
|
||||
rs1 = RsvpRequestRsvpSlot.find_by_rsvp_request_id(rsvp1.id)
|
||||
rs1.rsvp_slot_id.should == @slot1.id
|
||||
|
||||
# check before approving
|
||||
rs2 = RsvpRequestRsvpSlot.find_by_rsvp_request_id(rsvp2.id)
|
||||
rs2.rsvp_slot_id.should == @slot1.id
|
||||
|
||||
# approve RSVP 2 (same slot ID, but slot2 is same instrument + proficiency level)
|
||||
RsvpRequest.update({:id => rsvp2.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs2.id, :accept => true}]}, @session_creator)
|
||||
|
||||
# should have linked the RsvpRequestRsvpSlot record to the second slot
|
||||
rs2 = RsvpRequestRsvpSlot.find_by_rsvp_request_id(rsvp2.id)
|
||||
rs2.rsvp_slot_id.should == slot2.id
|
||||
|
||||
slots = RsvpSlot.where("music_session_id = ?", @music_session.id)
|
||||
slots.count.should == 2
|
||||
|
||||
request_slots = RsvpRequestRsvpSlot.where("chosen=true")
|
||||
request_slots.count.should == 2
|
||||
end
|
||||
|
||||
it "should create a new slot for an RSVP for a slot that has already been approved" do
|
||||
rsvp = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id, @slot2.id], :message => "Let's Jam!"}, @session_invitee)
|
||||
|
||||
# approve
|
||||
|
|
@ -239,7 +279,10 @@ describe RsvpRequest do
|
|||
# approve again
|
||||
rs1 = RsvpRequestRsvpSlot.find_by_rsvp_slot_id(@slot1.id)
|
||||
rs2 = RsvpRequestRsvpSlot.find_by_rsvp_slot_id(@slot2.id)
|
||||
expect {RsvpRequest.update({:id => rsvp.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => true}, {:request_slot_id => rs2.id, :accept => true}]}, @session_creator)}.to raise_error(StateError)
|
||||
RsvpRequest.update({:id => rsvp.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => true}, {:request_slot_id => rs2.id, :accept => true}]}, @session_creator)
|
||||
|
||||
slots = RsvpSlot.where("music_session_id = ?", @music_session.id)
|
||||
slots.count.should == 4
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
function beforeShow(data) {
|
||||
sessionId = data.id;
|
||||
console.log("sessionId=%o", sessionId);
|
||||
loadSessionData();
|
||||
}
|
||||
|
||||
|
|
@ -41,8 +40,7 @@
|
|||
function inviteMusicians(e) {
|
||||
e.preventDefault();
|
||||
|
||||
friendInput = inviteMusiciansUtil.inviteSessionUpdate('#update-session-invite-musicians',
|
||||
sessionId);
|
||||
friendInput = inviteMusiciansUtil.inviteSessionUpdate('#update-session-invite-musicians', sessionId);
|
||||
inviteMusiciansUtil.loadFriends();
|
||||
$(friendInput).show();
|
||||
// invitationDialog.showEmailDialog();
|
||||
|
|
@ -85,12 +83,55 @@
|
|||
e.preventDefault();
|
||||
|
||||
var rsvpId = $(e.target).attr('request-id');
|
||||
var userName = $(e.target).attr('user-name');
|
||||
var instrumentIds = $(e.target).attr('data-instrument-text');
|
||||
var params = buildRsvpRequestActionParams(rsvpId, true);
|
||||
|
||||
// first check if any open slots exist for these instruments
|
||||
rest.getOpenSessionSlots(sessionData.id, true)
|
||||
.done(function(openSlots) {
|
||||
if (openSlots) {
|
||||
if (openSlots.length === 0) {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName);
|
||||
}
|
||||
else {
|
||||
var arrInstrumentIds = instrumentIds.split('|');
|
||||
var openSlotInstrumentIds = [];
|
||||
var unavailableSlotInstrumentIds = [];
|
||||
|
||||
// ensure each instrument in the user's list is available in the open slots list
|
||||
$.each(openSlots, function(index, slot) {
|
||||
openSlotInstrumentIds.push(slot.instrument_id);
|
||||
});
|
||||
|
||||
// build list of instrument IDs in the RSVP request for which there are no open slots
|
||||
for (var i=0; i < arrInstrumentIds.length; i++) {
|
||||
if ($.inArray(arrInstrumentIds[i], openSlotInstrumentIds) === -1) {
|
||||
unavailableSlotInstrumentIds.push(arrInstrumentIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (unavailableSlotInstrumentIds.length > 0) {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, unavailableSlotInstrumentIds, userName, function() {
|
||||
approve(rsvpId, params);
|
||||
});
|
||||
}
|
||||
else {
|
||||
approve(rsvpId, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function approve(rsvpId, params) {
|
||||
rest.updateRsvpRequest(rsvpId, params)
|
||||
.done(refreshSessionDetail)
|
||||
.fail(function(jqXHR, textStatus, errorMessage) {
|
||||
if (jqXHR.status === 400) {
|
||||
if (jqXHR.status === 409) {
|
||||
app.notify(
|
||||
{
|
||||
title: "Unable to Approve RSVP",
|
||||
|
|
@ -284,11 +325,14 @@
|
|||
var latencyHtml = "";
|
||||
$.each(sessionData.pending_rsvp_requests, function(index, pending_rsvp_request) {
|
||||
if (pending_rsvp_request.user_id != context.JK.currentUserId) {
|
||||
var instrumentDesc = [];
|
||||
|
||||
if ("instrument_list" in pending_rsvp_request && pending_rsvp_request.instrument_list != null) {
|
||||
$.each(pending_rsvp_request.instrument_list, function (index, instrument) {
|
||||
var instrumentId = instrument == null ? null : instrument.id;
|
||||
var inst = context.JK.getInstrumentIcon24(instrumentId);
|
||||
instrumentLogoHtml += '<img title="' + instrumentId + '" hoveraction="instrument" data-instrument-id="' + instrumentId + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
instrumentDesc.push(instrumentId);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -304,7 +348,7 @@
|
|||
$templateAccountPendingRsvp.html(),
|
||||
{user_id: pending_rsvp_request.user_id, avatar_url: avatar_url,
|
||||
user_name: pending_rsvp_request.user.name, instruments: instrumentLogoHtml,
|
||||
latency: latencyHtml, request_id: pending_rsvp_request.id},
|
||||
latency: latencyHtml, request_id: pending_rsvp_request.id, instrument_text: instrumentDesc.join('|')},
|
||||
{variable: 'data'}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog('rsvp-cancel-dialog');
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
|
||||
$dialog = $('[layout-id="' + dialogId + '"]');
|
||||
|
||||
$("#rsvp-cancel-dialog").iCheck({
|
||||
$dialog.iCheck({
|
||||
checkboxClass: 'icheckbox_minimal',
|
||||
radioClass: 'iradio_minimal',
|
||||
inheritClass: true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.RsvpCreateSlotDialog = function(app, sessionId, instrumentIds, rsvpRequesterName, createSlotsCallback) {
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var $dialog = null;
|
||||
var dialogId = 'rsvp-create-slot-dialog';
|
||||
var $btnSave = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
var instructions = "All RSVP slots for the instruments below have already been filled. Would you like to open up a new RSVP slot for " + rsvpRequesterName + " so that they can join your session too?";
|
||||
var instruments = instrumentIds.join("<br/>");
|
||||
|
||||
$('.instructions', $dialog).html(instructions);
|
||||
$('.instruments', $dialog).html(instruments);
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
$btnSave.unbind('click');
|
||||
$btnSave.click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (createSlotsCallback) {
|
||||
createSlotsCallback();
|
||||
app.layout.closeDialog(dialogId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$dialog = $('[layout-id="' + dialogId + '"]');
|
||||
$btnSave = $dialog.find('.btnSave');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
}
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -30,17 +30,14 @@
|
|||
|
||||
var hasOpenSlots = response.open_slots && response.open_slots.length > 0;
|
||||
|
||||
|
||||
if (response['is_unstructured_rsvp?']) {
|
||||
var checkedState = hasOpenSlots ? '' : 'checked="checked"'
|
||||
$('.rsvp-instruments', $dialog).append('<input type="checkbox" ' + checkedState + ' value="unstructured"/>Play Any Instrument You Like<br/>');
|
||||
$('.rsvp-instruments', $dialog).append('<input type="checkbox" ' + checkedState + ' value="unstructured"/><span>Play Any Instrument You Like</span><br/>');
|
||||
}
|
||||
|
||||
if (hasOpenSlots) {
|
||||
$.each(response.open_slots, function(index, val) {
|
||||
var instrument = val.instrument_id;
|
||||
|
||||
$('.rsvp-instruments', $dialog).append('<input type="checkbox" value="' + val.id + '"/>' + val.description + " (" + val.proficiency_desc + ")<br/>");
|
||||
$('.rsvp-instruments', $dialog).append('<input type="checkbox" data-instrument-id="' + val.instrument_id + '" value="' + val.id + '"/><span>' + val.description + " (" + val.proficiency_desc + ")</span><br/>");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -60,18 +57,28 @@
|
|||
$btnSubmit.click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var error = false;
|
||||
var slotIds = [];
|
||||
var selectedSlots = [];
|
||||
$("input:checked", '.rsvp-instruments').each(function(index) {
|
||||
var selection = $(this).attr('data-instrument-id');
|
||||
|
||||
if ($.inArray(selection, selectedSlots) > -1) {
|
||||
$('.error', $dialog).html('You have selected the same instrument twice.').show();
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
selectedSlots.push(selection);
|
||||
slotIds.push($(this).val());
|
||||
});
|
||||
|
||||
if (error) return;
|
||||
|
||||
if (slotIds.length === 0) {
|
||||
$('.error', $dialog).show();
|
||||
$('.error', $dialog).html('You must select at least 1 instrument.').show();
|
||||
return;
|
||||
}
|
||||
|
||||
var error = false;
|
||||
|
||||
// TODO: show spinner??
|
||||
rest.submitRsvpRequest(sessionId, slotIds)
|
||||
.done(function(response) {
|
||||
|
|
@ -83,8 +90,7 @@
|
|||
})
|
||||
.fail(function(xhr, textStatus, errorMessage) {
|
||||
error = true;
|
||||
$('.error', $dialog).html("Unexpected error occurred while saving message (" + xhr.status + ")");
|
||||
$('.error', $dialog).show();
|
||||
$('.error', $dialog).html("Unexpected error occurred while saving message (" + xhr.status + ")").show();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -422,7 +422,7 @@
|
|||
var $action_btn = $notification.find($btnNotificationAction);
|
||||
$action_btn.text('SESSION DETAILS');
|
||||
$action_btn.click(function() {
|
||||
context.JK.popExternalLink('/sessions/' + payload.session_id + '/details');
|
||||
openSessionInfoWebPage({"session_id": payload.session_id});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -843,10 +843,12 @@
|
|||
}, [{
|
||||
id: "btn-more-info",
|
||||
text: "MORE INFO",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -865,10 +867,12 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-manage-rsvp",
|
||||
text: "Manage RSVP",
|
||||
"layout-action": "close",
|
||||
href: "/client#/account/sessionDetail/" + payload.session_id,
|
||||
"class": "button-orange"
|
||||
text: "MANAGE RSVP",
|
||||
"class": "button-orange",
|
||||
callback: navigateToSessionDetails,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -886,11 +890,14 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
text: "SESSION DETAILS",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -908,11 +915,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -930,11 +939,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -952,11 +963,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -974,11 +987,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -996,11 +1011,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -1019,11 +1036,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -1231,6 +1250,14 @@
|
|||
context.JK.popExternalLink('/recordings/' + args.recording_id);
|
||||
}
|
||||
|
||||
function navigateToSessionDetails(args) {
|
||||
context.location = '/client#/account/sessionDetail/' + args.session_id;
|
||||
}
|
||||
|
||||
function openSessionInfoWebPage(args) {
|
||||
context.JK.popExternalLink('/sessions/' + args.session_id + '/details');
|
||||
}
|
||||
|
||||
function deleteNotificationHandler(evt) {
|
||||
evt.stopPropagation();
|
||||
var notificationId = $(this).attr('notification-id');
|
||||
|
|
|
|||
|
|
@ -47,12 +47,19 @@
|
|||
return rsvpDialog.showDialog();
|
||||
}
|
||||
|
||||
function launchRsvpCreateSlotDialog(sessionId, instrumentIds, rsvpRequesterName, createSlotsCallback) {
|
||||
var rsvpDialog = new JK.RsvpCreateSlotDialog(JK.app, sessionId, instrumentIds, rsvpRequesterName, createSlotsCallback);
|
||||
rsvpDialog.initialize();
|
||||
return rsvpDialog.showDialog();
|
||||
}
|
||||
|
||||
this.addSessionLike = addSessionLike;
|
||||
this.addRecordingLike = addRecordingLike;
|
||||
this.launchCommentDialog = launchCommentDialog;
|
||||
this.launchShareDialog = launchShareDialog;
|
||||
this.launchRsvpSubmitDialog = launchRsvpSubmitDialog;
|
||||
this.launchRsvpCancelDialog = launchRsvpCancelDialog;
|
||||
this.launchRsvpCreateSlotDialog = launchRsvpCreateSlotDialog;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
|
||||
function togglePlay() {
|
||||
if(playing) {
|
||||
$status.text('SESSION IN PROGRESS');
|
||||
$status.text('LIVE SESSION IN PROGRESS');
|
||||
stopPlay();
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ class ApiController < ApplicationController
|
|||
@exception = exception
|
||||
render "errors/permission_error", :status => 403
|
||||
end
|
||||
rescue_from 'JamRuby::ConflictError' do |exception|
|
||||
@exception = exception
|
||||
render "errors/conflict_error", :status => 409
|
||||
end
|
||||
rescue_from 'ActiveRecord::RecordNotFound' do |exception|
|
||||
@@log.debug(exception)
|
||||
render :json => { :errors => { :resource => ["record not found"] } }, :status => 404
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@
|
|||
{{data.latency}}
|
||||
%td.rsvp-buttons
|
||||
%a{href: "/client#/profile/{{data.user_id}}", class: 'button-orange left', 'user-id' => "{{data.user_id}}"} PROFILE
|
||||
%a{href: "#", class: 'button-orange left approveRsvpRequest', 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}"} APPROVE
|
||||
%a{href: "#", class: 'button-orange left approveRsvpRequest', 'data-instrument-text' => "{{data.instrument_text}}", 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}", 'user-name' => "{{data.user_name}}"} APPROVE
|
||||
%a{href: "#", class: 'button-orange left declineRsvpRequest', 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}"} DECLINE
|
||||
.clearall
|
||||
.clearall
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
= render 'dialogs/commentDialog'
|
||||
= render 'dialogs/rsvpSubmitDialog'
|
||||
= render 'dialogs/rsvpCancelDialog'
|
||||
= render 'dialogs/rsvpCreateSlotDialog'
|
||||
= render 'dialogs/sessionCancelDialog'
|
||||
= render 'dialogs/signinDialog'
|
||||
= render 'dialogs/signupDialog'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
.dialog.dialog-overlay-sm layout='dialog' layout-id='rsvp-create-slot-dialog' id='rsvp-create-slot-dialog'
|
||||
.content-head
|
||||
= image_tag "content/icon_alert.png", {:width => 24, :height => 24, :class => 'content-icon' }
|
||||
h1 RSVP Slot Already Filled
|
||||
|
||||
.dialog-inner
|
||||
div.instructions
|
||||
br
|
||||
div.instruments
|
||||
.buttons
|
||||
.right
|
||||
a.button-grey class='btnCancel' layout-action='cancel' NO
|
||||
a.button-orange class='btnSave' YES
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
.schedule-recurrence
|
||||
.part
|
||||
.slot-instructions Check the box(es) next to the track(s) you want to play in the session:
|
||||
.error{:style => 'display:none'} You must select at least 1 instrument.
|
||||
.error{:style => 'display:none'}
|
||||
.rsvp-instruments
|
||||
|
||||
.comment-instructions Enter a message to the other musicians in the session (optional):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
object @exception
|
||||
|
||||
attributes :message
|
||||
|
||||
node "type" do
|
||||
"ConflictError"
|
||||
end
|
||||
Loading…
Reference in New Issue