done
This commit is contained in:
parent
77232d9e0a
commit
4d9e8d2847
|
|
@ -1,3 +1,21 @@
|
|||
ALTER TABLE rsvp_requests ADD COLUMN music_session_id VARCHAR(64) REFERENCES music_sessions(id);
|
||||
ALTER TABLE rsvp_requests ADD COLUMN chosen boolean DEFAULT FALSE NOT NULL;
|
||||
|
||||
UPDATE rsvp_requests set CHOSEN = TRUE, music_session_id = b.music_session_id FROM (
|
||||
|
||||
SELECT music_sessions.id as music_session_id, rsvp_requests.id as rsvp_request_id FROM music_sessions JOIN
|
||||
rsvp_slots
|
||||
ON
|
||||
music_sessions.id = rsvp_slots.music_session_id
|
||||
JOIN
|
||||
rsvp_requests_rsvp_slots
|
||||
ON
|
||||
rsvp_requests_rsvp_slots.rsvp_slot_id = rsvp_slots.id
|
||||
JOIN
|
||||
rsvp_requests
|
||||
ON rsvp_requests.id = rsvp_requests_rsvp_slots.rsvp_request_id
|
||||
WHERE rsvp_requests_rsvp_slots.chosen = TRUE
|
||||
) b WHERE rsvp_requests.id = rsvp_request_id;
|
||||
|
||||
ALTER TABLE music_sessions ADD COLUMN friends_can_join boolean DEFAULT FALSE NOT NULL;
|
||||
CREATE INDEX rsvp_request_music_session_id ON rsvp_requests USING btree (music_session_id);
|
||||
|
|
@ -243,7 +243,6 @@ module JamRuby
|
|||
return query
|
||||
end
|
||||
|
||||
|
||||
# all sessions that are private and active, yet I can see
|
||||
def self.friend_active_index(user, options)
|
||||
|
||||
|
|
@ -264,7 +263,7 @@ module JamRuby
|
|||
|
||||
LEFT OUTER JOIN
|
||||
rsvp_requests
|
||||
ON rsvp_requests.music_session_id = music_sessions.id and rsvp_requests.user_id = '#{user.id}' AND rsvp_requests.chosen = true
|
||||
ON rsvp_requests.music_session_id = active_music_sessions.id and rsvp_requests.user_id = '#{user.id}' AND rsvp_requests.chosen = true
|
||||
|
||||
LEFT OUTER JOIN
|
||||
invitations
|
||||
|
|
@ -297,7 +296,8 @@ module JamRuby
|
|||
query = query.where('music_sessions.language = ?', lang) unless lang.blank?
|
||||
query = query.where('music_sessions.id = ?', session_id) unless session_id.blank?
|
||||
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", ActiveRecord::Base.connection.quote(keyword) + ':*') unless keyword.blank?
|
||||
query = query.group("music_sessions.id")
|
||||
query = query.group("music_sessions.id, active_music_sessions.created_at")
|
||||
query = query.order("active_music_sessions.created_at DESC")
|
||||
query
|
||||
end
|
||||
|
||||
|
|
@ -331,7 +331,8 @@ module JamRuby
|
|||
query = query.where('music_sessions.language = ?', lang) unless lang.blank?
|
||||
query = query.where('music_sessions.id = ?', session_id) unless session_id.blank?
|
||||
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", ActiveRecord::Base.connection.quote(keyword) + ':*') unless keyword.blank?
|
||||
query = query.group("music_sessions.id")
|
||||
query = query.group("music_sessions.id, active_music_sessions.created_at")
|
||||
query = query.order("active_music_sessions.created_at DESC")
|
||||
query
|
||||
end
|
||||
|
||||
|
|
@ -766,6 +767,10 @@ module JamRuby
|
|||
self.save
|
||||
end
|
||||
|
||||
def friends_can_join
|
||||
music_session.friends_can_join
|
||||
end
|
||||
|
||||
def invitations
|
||||
music_session.invitations
|
||||
end
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ module JamRuby
|
|||
validates :fan_access, :inclusion => {:in => [true, false]}
|
||||
validates :approval_required, :inclusion => {:in => [true, false]}
|
||||
validates :musician_access, :inclusion => {:in => [true, false]}
|
||||
validates :friends_can_join, :inclusion => {:in => [true, false]}
|
||||
validates :is_unstructured_rsvp, :inclusion => {:in => [true, false]}
|
||||
validates :legal_terms, :inclusion => {:in => [true]}, :on => :create
|
||||
validates :creator, :presence => true
|
||||
|
|
@ -333,6 +334,7 @@ module JamRuby
|
|||
new_session.scheduled_duration = self.scheduled_duration
|
||||
new_session.musician_access = self.musician_access
|
||||
new_session.approval_required = self.approval_required
|
||||
new_session.friends_can_join = self.friends_can_join
|
||||
new_session.fan_chat = self.fan_chat
|
||||
new_session.genre_id = self.genre_id
|
||||
new_session.legal_policy = self.legal_policy
|
||||
|
|
@ -463,6 +465,13 @@ module JamRuby
|
|||
tracks
|
||||
end
|
||||
|
||||
# is the viewer 'friensd with the session?'
|
||||
# practically, to be a friend with the session, you have to be a friend with the creator
|
||||
# we could loosen to be friend of friends or friends with anyone in the session
|
||||
def friends_with_session(user)
|
||||
self.creator.friends?(user)
|
||||
end
|
||||
|
||||
def can_join? user, as_musician
|
||||
if as_musician
|
||||
unless user.musician
|
||||
|
|
@ -475,10 +484,9 @@ module JamRuby
|
|||
else
|
||||
return true
|
||||
end
|
||||
|
||||
else
|
||||
# the creator can always join, and the invited users can join
|
||||
return self.creator == user || self.invited_musicians.exists?(user.id) || self.approved_rsvps.include?(user)
|
||||
return self.creator == user || self.invited_musicians.exists?(user.id) || self.approved_rsvps.include?(user) || (self.friends_can_join && self.friends_with_session(user))
|
||||
end
|
||||
else
|
||||
# it's a fan, and the only way a fan can join is if fan_access is true
|
||||
|
|
@ -490,7 +498,7 @@ module JamRuby
|
|||
if self.musician_access || self.fan_access
|
||||
true
|
||||
else
|
||||
self.creator == user || self.invited_musicians.exists?(user.id) || self.approved_rsvps.include?(user) || self.has_lesson_access?(user)
|
||||
self.creator == user || self.invited_musicians.exists?(user.id) || self.approved_rsvps.include?(user) || self.creator.friends?(user) || self.has_lesson_access?(user)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -637,6 +645,7 @@ module JamRuby
|
|||
ms.description = options[:description]
|
||||
ms.genre_id = (options[:genres].length > 0 ? options[:genres][0] : nil) if options[:genres]
|
||||
ms.musician_access = options[:musician_access]
|
||||
ms.friends_can_join = options[:friends_can_join]
|
||||
ms.approval_required = options[:approval_required]
|
||||
ms.fan_access = options[:fan_access]
|
||||
ms.fan_chat = options[:fan_chat]
|
||||
|
|
@ -1115,6 +1124,99 @@ SQL
|
|||
[music_sessions, user_scores]
|
||||
end
|
||||
|
||||
|
||||
def self.scheduled_index(user, options)
|
||||
session_id = options[:session_id]
|
||||
genre = options[:genre]
|
||||
lang = options[:lang]
|
||||
keyword = options[:keyword]
|
||||
offset = options[:offset]
|
||||
limit = options[:limit]
|
||||
day = options[:day]
|
||||
timezone_offset = options[:timezone_offset]
|
||||
|
||||
query = MusicSession.select('music_sessions.*')
|
||||
query = query.where("old = FALSE")
|
||||
query = query.where("scheduled_start IS NULL OR scheduled_start > (NOW() - (interval '15 minute'))")
|
||||
query = query.where("music_sessions.canceled = FALSE")
|
||||
query = query.where("description != 'Jam Track Session'")
|
||||
query = query.where("music_sessions.id NOT IN (SELECT id FROM active_music_sessions)")
|
||||
# one flaw in the join below is that we only consider if the creator of the session has asked you to be your friend, but you have not accepted. While this means you may always see a session by someone you haven't friended, the goal is to match up new users more quickly
|
||||
query = query.joins(
|
||||
%Q{
|
||||
|
||||
LEFT OUTER JOIN
|
||||
rsvp_requests
|
||||
ON rsvp_requests.music_session_id = music_sessions.id and rsvp_requests.user_id = '#{user.id}' AND rsvp_requests.chosen = true
|
||||
|
||||
LEFT OUTER JOIN
|
||||
invitations
|
||||
ON
|
||||
music_sessions.id = invitations.music_session_id AND invitations.receiver_id = '#{user.id}'
|
||||
LEFT OUTER JOIN
|
||||
friendships
|
||||
ON
|
||||
music_sessions.user_id = friendships.user_id AND friendships.friend_id = '#{user.id}'
|
||||
LEFT OUTER JOIN
|
||||
friendships as friendships_2
|
||||
ON
|
||||
music_sessions.user_id = friendships_2.friend_id AND friendships_2.user_id = '#{user.id}'
|
||||
}
|
||||
)
|
||||
|
||||
# keep only rsvp/invitation/friend results. Nice tailored active list now!
|
||||
query = query.where("open_rsvps = TRUE OR rsvp_requests.id IS NOT NULL OR invitations.id IS NOT NULL or music_sessions.user_id = '#{user.id}' OR (friendships.id IS NOT NULL AND friendships_2.id IS NOT NULL)")
|
||||
|
||||
|
||||
# if not specified, default offset to 0
|
||||
offset ||= 0
|
||||
offset = offset.to_i
|
||||
# if not specified, default limit to 20
|
||||
limit ||= 20
|
||||
limit = limit.to_i
|
||||
|
||||
query = query.offset(offset)
|
||||
query = query.limit(limit)
|
||||
query = query.where("music_sessions.genre_id = ?", genre) unless genre.blank?
|
||||
query = query.where('music_sessions.language = ?', lang) unless lang.blank?
|
||||
query = query.where('music_sessions.id = ?', session_id) unless session_id.blank?
|
||||
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", ActiveRecord::Base.connection.quote(keyword) + ':*') unless keyword.blank?
|
||||
query = query.group("music_sessions.id, music_sessions.scheduled_start")
|
||||
query = query.order("music_sessions.scheduled_start DESC")
|
||||
|
||||
if !day.blank? && !timezone_offset.blank?
|
||||
begin
|
||||
day = Date.parse(day)
|
||||
next_day = day + 1
|
||||
timezone_offset = timezone_offset.to_i
|
||||
if timezone_offset == 0
|
||||
timezone_offset = '' # no offset to specify in this case
|
||||
elsif timezone_offset > 0
|
||||
timezone_offset = "+#{timezone_offset}"
|
||||
end
|
||||
query = query.where("scheduled_start BETWEEN TIMESTAMP WITH TIME ZONE '#{day} 00:00:00#{timezone_offset}'
|
||||
AND TIMESTAMP WITH TIME ZONE '#{next_day} 00:00:00#{timezone_offset}'")
|
||||
rescue Exception => e
|
||||
# do nothing. bad date probably
|
||||
@@log.warn("unable to parse day=#{day}, timezone_offset=#{timezone_offset}, e=#{e}")
|
||||
end
|
||||
else
|
||||
sql =<<SQL
|
||||
music_sessions.started_at IS NULL AND
|
||||
(music_sessions.created_at > NOW() - interval '#{UNSTARTED_INTERVAL_DAYS_SKIP} days' OR
|
||||
music_sessions.scheduled_start > NOW() - interval '#{UNSTARTED_INTERVAL_DAYS_SKIP} days')
|
||||
SQL
|
||||
query = query.where(sql)
|
||||
end
|
||||
|
||||
#FROM music_sessions
|
||||
# WHERE old = FALSE AND (scheduled_start IS NULL OR scheduled_start > (NOW() - (interval '15 minute')))
|
||||
# AND canceled = FALSE AND description != 'Jam Track Session'
|
||||
# AND id NOT IN (SELECT id FROM active_music_sessions);
|
||||
|
||||
query
|
||||
end
|
||||
|
||||
# returns a single session, but populates any other user info with latency scores, so that show_history.rabl can do it's business
|
||||
def self.session_with_scores(current_user, music_session_id, include_pending=false)
|
||||
MusicSession.sms_init(current_user, {session_id: music_session_id}, include_pending)
|
||||
|
|
|
|||
|
|
@ -672,9 +672,11 @@ module JamRuby
|
|||
@@mq_router.server_publish_to_session(active_music_session, msg)
|
||||
end
|
||||
|
||||
# tell all your friends you joined a session
|
||||
def send_musician_session_join(music_session, user)
|
||||
|
||||
if music_session.musician_access || music_session.fan_access
|
||||
# tell the creator's friends that they joined a session, because we changed Find session to show your friend's sessions
|
||||
if music_session.creator.id == user.id || music_session.musician_access || music_session.fan_access
|
||||
|
||||
friends = Friendship.where(:friend_id => user.id)
|
||||
user_followers = user.followers
|
||||
|
|
@ -689,14 +691,14 @@ module JamRuby
|
|||
notification_msg = format_msg(NotificationTypes::MUSICIAN_SESSION_JOIN, {:user => user})
|
||||
|
||||
friends_and_followers.each do |ff|
|
||||
notification = Notification.new
|
||||
notification.description = NotificationTypes::MUSICIAN_SESSION_JOIN
|
||||
notification.source_user_id = user.id
|
||||
notification.target_user_id = ff.id
|
||||
notification.session_id = music_session.id
|
||||
notification.save
|
||||
|
||||
if ff.online?
|
||||
notification = Notification.new
|
||||
notification.description = NotificationTypes::MUSICIAN_SESSION_JOIN
|
||||
notification.source_user_id = user.id
|
||||
notification.target_user_id = ff.id
|
||||
notification.session_id = music_session.id
|
||||
notification.save
|
||||
|
||||
msg = @@message_factory.musician_session_join(
|
||||
ff.id,
|
||||
music_session.id,
|
||||
|
|
@ -710,15 +712,6 @@ module JamRuby
|
|||
)
|
||||
|
||||
@@mq_router.publish_to_user(ff.id, msg)
|
||||
|
||||
else
|
||||
# if APP_CONFIG.send_join_session_email_notifications
|
||||
# begin
|
||||
# UserMailer.musician_session_join(ff, notification_msg, music_session.id).deliver_now
|
||||
# rescue => e
|
||||
# @@log.error("Unable to send MUSICIAN_SESSION_JOIN email to user #{ff.email} #{e}")
|
||||
# end
|
||||
# end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -495,6 +495,105 @@ describe MusicSession do
|
|||
end
|
||||
end
|
||||
|
||||
describe "sms_index_2" do
|
||||
describe "simple" do
|
||||
let(:conn) { FactoryGirl.create(:connection, user: creator, locidispid: creator.last_jam_locidispid) }
|
||||
let(:searcher) { FactoryGirl.create(:user, last_jam_locidispid: 2) }
|
||||
let(:searcher_conn) { FactoryGirl.create(:connection, user: searcher, ip_address: '2.2.2.2', locidispid: searcher.last_jam_locidispid) }
|
||||
let(:default_opts) { {client_id: searcher_conn.client_id} }
|
||||
let(:network_score) { 20 }
|
||||
|
||||
it "no results" do
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
end
|
||||
|
||||
it "one session shows/hides based on open_rsvps" do
|
||||
|
||||
music_session = FactoryGirl.create(:music_session, creator: creator, scheduled_start: nil)
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 1
|
||||
|
||||
music_session.open_rsvps = false
|
||||
music_session.save!
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 0
|
||||
end
|
||||
|
||||
|
||||
it "one session, one RSVP (creator)" do
|
||||
music_session = FactoryGirl.create(:music_session, creator: creator)
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 1
|
||||
end
|
||||
|
||||
it "skip session with past due scheduled_start time" do
|
||||
interval = MusicSession::UNSTARTED_INTERVAL_DAYS_SKIP
|
||||
dd = Time.now - (interval.to_i + 1).days
|
||||
Timecop.travel(dd)
|
||||
msess1 = FactoryGirl.create(:music_session, creator: creator, scheduled_start: dd)
|
||||
msess2 = FactoryGirl.create(:music_session, creator: creator)
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 1
|
||||
expect(music_sessions[0].id).to eq(msess2.id)
|
||||
end
|
||||
|
||||
it "filters sessions in the past" do
|
||||
|
||||
music_session = FactoryGirl.create(:music_session, creator: creator)
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 1
|
||||
|
||||
# 15 minutes is the edge of forgiveness
|
||||
music_session.scheduled_start = 16.minutes.ago
|
||||
music_session.save!
|
||||
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 0
|
||||
|
||||
# this should still fall in time
|
||||
music_session.scheduled_start = 14.minutes.ago
|
||||
music_session.save!
|
||||
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 1
|
||||
end
|
||||
|
||||
it "one session, one RSVP (creator), one invitation" do
|
||||
# create an invitee, and friend them with the creator (you have to be friends to send an invite)
|
||||
invitee = FactoryGirl.create(:user)
|
||||
FactoryGirl.create(:friendship, user: creator, friend: invitee)
|
||||
FactoryGirl.create(:friendship, user: invitee, friend: creator)
|
||||
music_session = FactoryGirl.create(:music_session, creator: creator)
|
||||
FactoryGirl.create(:invitation, receiver:invitee, sender:creator, music_session: music_session)
|
||||
|
||||
music_sessions = MusicSession.scheduled_index(searcher, default_opts)
|
||||
music_sessions.length.should == 1
|
||||
|
||||
#search with the invitee this time.
|
||||
invitee_conn = FactoryGirl.create(:connection, user: invitee)
|
||||
music_sessions = MusicSession.scheduled_index(invitee, {})
|
||||
music_sessions.length.should == 1
|
||||
end
|
||||
|
||||
it "does not show when it goes active" do
|
||||
# we create a scheduled session--it should return
|
||||
music_session = FactoryGirl.create(:music_session, creator: creator, scheduled_start: nil)
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 1
|
||||
|
||||
# but then make an active session for this scheduled session
|
||||
ams = FactoryGirl.create(:active_music_session, music_session: music_session, creator: creator, musician_access: true)
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 0
|
||||
|
||||
# finally, delete the active session, and see results go back to one
|
||||
ams.delete
|
||||
music_sessions = MusicSession.scheduled_index(searcher, {})
|
||||
music_sessions.length.should == 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
describe "sms_index", no_transaction: true do
|
||||
|
||||
describe "simple" do
|
||||
|
|
|
|||
|
|
@ -66,6 +66,11 @@
|
|||
$('#session-settings-fan-access').val('listen-chat-band');
|
||||
}
|
||||
|
||||
// friends can join
|
||||
|
||||
var friendsCanJoinValue = currentSession.friends_can_join ? "true" : "false"
|
||||
$('#session-settings-friends-can-join').val(friendsCanJoinValue)
|
||||
|
||||
var $controllerSelect = $('#session-settings-master-mix-controller')
|
||||
|
||||
$controllerSelect.empty()
|
||||
|
|
@ -98,12 +103,14 @@
|
|||
context.JK.dropdown($('#session-settings-language'));
|
||||
context.JK.dropdown($('#session-settings-musician-access'));
|
||||
context.JK.dropdown($('#session-settings-fan-access'));
|
||||
context.JK.dropdown($('#session-settings-friends-can-join'));
|
||||
context.JK.dropdown($('#session-settings-master-mix-controller'));
|
||||
|
||||
var easyDropDownState = canPlayWithOthers.canPlay ? 'enable' : 'disable'
|
||||
$('#session-settings-musician-access').easyDropDown(easyDropDownState)
|
||||
$('#session-settings-fan-access').easyDropDown(easyDropDownState)
|
||||
|
||||
|
||||
}
|
||||
|
||||
function addNotation(notation) {
|
||||
|
|
@ -164,7 +171,15 @@
|
|||
data.fan_access = true;
|
||||
data.fan_chat = true;
|
||||
}
|
||||
|
||||
|
||||
var friendsCanJoin = $('#session-settings-friends-can-join').val();
|
||||
if (friendsCanJoin == 'true') {
|
||||
data.friends_can_join = true
|
||||
}
|
||||
else {
|
||||
data.friends_can_join = false
|
||||
}
|
||||
|
||||
rest.updateSession($('#session-settings-id').val(), data).done(settingsSaved)
|
||||
.done(function(response) {
|
||||
context.SessionActions.updateSession.trigger(response);
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@
|
|||
$action_btn.click(function() {
|
||||
openTerms(payload);
|
||||
});
|
||||
context.SessionsActions.updateSession(payload.session_id)
|
||||
}
|
||||
|
||||
else if (type === context.JK.MessageType.JOIN_REQUEST_REJECTED) {
|
||||
|
|
@ -740,6 +741,8 @@
|
|||
|
||||
handleNotification(payload, header.type);
|
||||
|
||||
context.SessionsActions.updateSession(payload.session_id)
|
||||
|
||||
app.notify({
|
||||
"title": "Session Invitation",
|
||||
"text": payload.msg
|
||||
|
|
@ -810,18 +813,12 @@
|
|||
var showNotification = false;
|
||||
var callback;
|
||||
if (context.JK.currentUserMusician) {
|
||||
// user is MUSICIAN; musician_access = TRUE
|
||||
if (payload.musician_access) {
|
||||
showNotification = true;
|
||||
okText = "JOIN";
|
||||
callback = joinSession;
|
||||
}
|
||||
// user is MUSICIAN; fan_access = TRUE
|
||||
else if (payload.fan_access) {
|
||||
showNotification = true;
|
||||
okText = "LISTEN";
|
||||
callback = listenToSession;
|
||||
}
|
||||
|
||||
context.SessionsActions.updateSession(payload.session_id)
|
||||
|
||||
showNotification = true;
|
||||
okText = "JOIN";
|
||||
callback = joinSession;
|
||||
}
|
||||
else {
|
||||
// user is FAN; fan_access = TRUE
|
||||
|
|
|
|||
|
|
@ -1,37 +1,18 @@
|
|||
context = window
|
||||
|
||||
SessionsActions = @SessionsActions
|
||||
|
||||
@FindSessionFriends = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(@AppStore, "onAppInit")]
|
||||
mixins: [Reflux.listenTo(@AppStore, "onAppInit")
|
||||
Reflux.listenTo(@SessionsStore, "onSessionsChanged")]
|
||||
|
||||
LIMIT: 50
|
||||
TYPE_SESSION: 'my'
|
||||
searched_ever: false
|
||||
registeredInfiniteScroll: false
|
||||
|
||||
getInitialState: () ->
|
||||
{sessions: [], currentPage: 0, next: null, searching: false, count: 0}
|
||||
|
||||
|
||||
search: () ->
|
||||
return if @state.searching
|
||||
|
||||
$root = $(@getDOMNode())
|
||||
# disable scroll watching now that we've started a new search
|
||||
$root.find('.content-body-scroller').off('scroll')
|
||||
$root.find('.end-of-sessions-list').hide()
|
||||
|
||||
|
||||
# we have to make sure the query starts from page 1, and no 'next' from previous causes a 'since' to show up
|
||||
query = @defaultQuery({page: 0})
|
||||
delete query.since
|
||||
@rest.findFriendSessions(query)
|
||||
.done((response) =>
|
||||
@setState({sessions: response.sessions, searching: false, first_search: false, currentPage: 1})
|
||||
)
|
||||
.fail((jqXHR) =>
|
||||
@app.notifyServerError jqXHR, 'Search Unavailable'
|
||||
@setState({searching: false, first_search: false})
|
||||
)
|
||||
|
||||
@setState({currentPage: 0, sessions:[], searching: true})
|
||||
{active: false, sessions: [], searching: false, count: 0, currentPage: 0, end:false}
|
||||
|
||||
sessionResults: () ->
|
||||
results = []
|
||||
|
|
@ -39,110 +20,143 @@ context = window
|
|||
results.push(`<FindSessionRow session={session} />`)
|
||||
results
|
||||
|
||||
help: () ->
|
||||
`<div className="find-session-help">
|
||||
<h3>How This Page Works</h3>
|
||||
<p>This page will show sessions tailored for you:</p>
|
||||
<ul>
|
||||
<li>sessions created by a friend (<a href='#' onClick={this.inviteFriends.bind(this)}>invite others to JamKazam!</a>)</li>
|
||||
<li>sessions for which you have an invitation</li>
|
||||
<li>sessions for which you have a RSVP</li>
|
||||
</ul>
|
||||
<br/>
|
||||
<h3>Sit Back and Relax</h3>
|
||||
<p>This page will automatically update when a friend creates a session, or you are invited to one.</p>
|
||||
<p>So if your friend is creating a session soon, just sit tight and watch for sessions to show up!</p>
|
||||
</div>`
|
||||
|
||||
refresh: () ->
|
||||
if @state.searching
|
||||
return
|
||||
|
||||
SessionsActions.clearSessions.trigger(@TYPE_SESSION, @query())
|
||||
|
||||
render: () ->
|
||||
results = @sessionResults()
|
||||
|
||||
className = "sessions-for-me"
|
||||
className = "content-body-scroller sessions-for-me"
|
||||
|
||||
if(@props.active)
|
||||
className = className + " active"
|
||||
|
||||
firstTime = null
|
||||
if results.length == 0
|
||||
if @state.searching
|
||||
results = `<tr key="single"><td colSpan="3" className="none-found">... Searching ...</td></tr>`
|
||||
else
|
||||
# help = @help()
|
||||
results = `<tr key="single"><td colSpan="3" className="none-found">None Found</td></tr>`
|
||||
|
||||
help = @help()
|
||||
|
||||
refreshButtonClasses = "button-grey btn-refresh"
|
||||
|
||||
if @state.searching
|
||||
refreshButtonClasses = refreshButtonClasses += " disabled"
|
||||
|
||||
`<div className={className}>
|
||||
<div className="content-body-scroller">
|
||||
<div className="content-wrapper">
|
||||
<div id="sessions-active" className="session-container">
|
||||
<div className="header-zone">
|
||||
<h2>sessions for me</h2>
|
||||
<div className="content-wrapper">
|
||||
<div id="sessions-active" className="session-container">
|
||||
<div className="header-zone">
|
||||
<h2>sessions for me</h2>
|
||||
|
||||
|
||||
<div className="refresh-btn">
|
||||
<a href="/client#/findSession" style={{textDecoration:'none'}}
|
||||
className="button-grey btn-refresh">REFRESH<span class="extra"></span></a>
|
||||
</div>
|
||||
<div className="search-box">
|
||||
<input className="session-keyword-srch" type="text" name="search"
|
||||
placeholder="Search by Keyword"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div className="findsession-container">
|
||||
<table id="sessions-active" className="findsession-table" cellspacing="0"
|
||||
cellpadding="0" border="0">
|
||||
<tr>
|
||||
<th align="left" width="40%">SESSION</th>
|
||||
<th align="left" width="45%">MUSICIANS</th>
|
||||
<th align="left" width="10%" style={{textAlign:'center'}}>ACTIONS</th>
|
||||
</tr>
|
||||
{results}
|
||||
</table>
|
||||
<div className="refresh-btn">
|
||||
<a href="/client#/findSession" style={{textDecoration:'none'}} disabled={this.state.searching}
|
||||
className={refreshButtonClasses} onClick={this.refresh.bind(this)}>REFRESH<span class="extra"></span></a>
|
||||
</div>
|
||||
<div className="search-box">
|
||||
<input className="session-keyword-srch" type="text" name="search"
|
||||
placeholder="Search by Keyword"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div className="findsession-container">
|
||||
<table id="sessions-active" className="findsession-table" cellspacing="0"
|
||||
cellpadding="0" border="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left" width="40%">SESSION</th>
|
||||
<th align="left" width="45%">MUSICIANS</th>
|
||||
<th align="left" width="10%" style={{textAlign:'center'}}>ACTIONS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{results}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{help}
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
query: () ->
|
||||
|
||||
defaultQuery: (extra) ->
|
||||
$root = $(this.getDOMNode())
|
||||
keyword = $root.find('input.session-keyword-srch').val()
|
||||
if keyword == ''
|
||||
keyword = undefined
|
||||
query =
|
||||
limit: @LIMIT
|
||||
offset: @state.currentPage * @LIMIT
|
||||
keyword: keyword
|
||||
|
||||
query
|
||||
|
||||
$.extend(query, extra)
|
||||
|
||||
componentDidMount: () ->
|
||||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@logger = context.JK.logger
|
||||
|
||||
@search()
|
||||
|
||||
componentDidUpdate: () ->
|
||||
componentDidUpdate: (prevProps, prevState) ->
|
||||
|
||||
if @props.active && !prevProps.active && !@searched_ever
|
||||
SessionsActions.updateSessions.trigger('my')
|
||||
@searched_ever = true
|
||||
|
||||
$root = $(this.getDOMNode())
|
||||
$scroller = $root.find('.content-body-scroller')
|
||||
$scroller = $root
|
||||
|
||||
if @state.next == null
|
||||
$scroller = $root.find('.content-body-scroller')
|
||||
# if we less results than asked for, end searching
|
||||
#$scroller.infinitescroll 'pause'
|
||||
$scroller.off('scroll')
|
||||
if @state.currentPage == 1 and @state.sessions.length == 0
|
||||
$root.find('.end-of-sessions-list').text('No friend sessions found').show()
|
||||
@logger.debug("FindSessions: empty search")
|
||||
else if @state.currentPage > 0
|
||||
$noMoreSessions = $root.find('.end-of-sessions-list').text('No more sessions').show()
|
||||
# there are bugs with infinitescroll not removing the 'loading'.
|
||||
# it's most noticeable at the end of the list, so whack all such entries
|
||||
else
|
||||
if !@registeredInfiniteScroll
|
||||
@registerInfiniteScroll($scroller)
|
||||
|
||||
registerInfiniteScroll: ($scroller) ->
|
||||
@registeredInfiniteScroll = true
|
||||
|
||||
$scroller.off('scroll')
|
||||
$scroller.on('scroll', () =>
|
||||
|
||||
# be sure to not fire off many refreshes when user hits the bottom
|
||||
return if @refreshing
|
||||
return if @state.searching
|
||||
|
||||
if @state.end
|
||||
return
|
||||
|
||||
if $scroller.scrollTop() + $scroller.innerHeight() + 100 >= $scroller[0].scrollHeight
|
||||
$scroller.append('<div class="infinite-scroll-loader-2">... Loading more Sessions ...</div>')
|
||||
@refreshing = true
|
||||
@logger.debug("refreshing more sessions for infinite scroll")
|
||||
@setState({searching: true})
|
||||
@rest.findFriendSessions(@defaultQuery())
|
||||
.done((json) =>
|
||||
@setState({
|
||||
sessions: @state.sessions.concat(json.sessions),
|
||||
currentPage: @state.currentPage + 1
|
||||
})
|
||||
)
|
||||
.always(() =>
|
||||
$scroller.find('.infinite-scroll-loader-2').remove()
|
||||
@refreshing = false
|
||||
@setState({searching: false})
|
||||
)
|
||||
SessionsActions.updateSessions.trigger(@TYPE_SESSION, @query())
|
||||
)
|
||||
|
||||
inviteFriends:() ->
|
||||
JK.InvitationDialogInstance.showEmailDialog();
|
||||
|
||||
onAppInit: (@app) ->
|
||||
return
|
||||
|
||||
onSessionsChanged: (sessionsChanged) ->
|
||||
if sessionsChanged.type == @TYPE_SESSION
|
||||
@setState(sessionsChanged)
|
||||
|
||||
})
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
context = window
|
||||
|
||||
SessionsActions = @SessionsActions
|
||||
|
||||
@FindSessionOpen = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(@AppStore, "onAppInit")
|
||||
Reflux.listenTo(@SessionsStore, "onSessionsChanged")]
|
||||
|
||||
searched_ever: false
|
||||
registeredInfiniteScroll: false
|
||||
|
||||
getInitialState: () ->
|
||||
{active: false, sessions: [], searching: false, count: 0, currentPage: 0, end: false}
|
||||
|
||||
sessionResults: () ->
|
||||
results = []
|
||||
for session in @state.sessions
|
||||
results.push(`<FindSessionRow mode={this.props.mode} session={session} />`)
|
||||
results
|
||||
|
||||
help: () ->
|
||||
if this.props.mode == 'open'
|
||||
`<div className="find-session-help">
|
||||
<h3>How This Page Works</h3>
|
||||
<p>This page will show only public jam sessions.</p>
|
||||
<p>Most recent sessions are shown an the top.</p>
|
||||
<p>This list of public sessions does not auto-update. You will have to push the REFRESH button to see new sessions.</p>
|
||||
</div>`
|
||||
else if this.props.mode == 'my'
|
||||
`<div className="find-session-help">
|
||||
<h3>How This Page Works</h3>
|
||||
<p>This page will show sessions tailored for you:</p>
|
||||
<ul>
|
||||
<li>sessions created by a friend (<a href='#' onClick={this.inviteFriends.bind(this)}>invite others to JamKazam</a>)</li>
|
||||
<li>sessions for which you have an invitation</li>
|
||||
<li>sessions for which you have a RSVP</li>
|
||||
</ul>
|
||||
<br/>
|
||||
<h3>Sit Back and Relax</h3>
|
||||
<p>This page will automatically update when a friend creates a session, or you are invited to one.</p>
|
||||
<p>So if your friend is creating a session soon, just sit tight and watch for sessions to show up!</p>
|
||||
</div>`
|
||||
else
|
||||
`<div className="find-session-help">
|
||||
<h3>How This Page Works</h3>
|
||||
<p>This page will show these scheduled sessions:</p>
|
||||
<ul>
|
||||
<li>public jam sessions</li>
|
||||
<li>sessions created by a friend (<a href='#' onClick={this.inviteFriends.bind(this)}>invite others to JamKazam</a>)</li>
|
||||
<li>sessions for which you have an invitation</li>
|
||||
<li>sessions for which you have a RSVP</li>
|
||||
</ul>
|
||||
<br/>
|
||||
<h3>Reserve a spot</h3>
|
||||
<p>If you find a session you are interested in attending later, then click the RSVP icon to reserve your spot.</p><p>An email will be sent to the creator of the session, and they can then approve your request.</p>
|
||||
<h3>Schedule your Own</h3>
|
||||
<p>Don't see a session you like? You can schedule your own session for others to RSVP to at the <a href="/client#/createSession">create session</a> screen. You will receive emails when others RSVP.</p>
|
||||
</div>`
|
||||
|
||||
|
||||
refresh: () ->
|
||||
if @state.searching
|
||||
return
|
||||
|
||||
SessionsActions.clearSessions.trigger(@props.mode, @query())
|
||||
|
||||
render: () ->
|
||||
results = @sessionResults()
|
||||
|
||||
className = "content-body-scroller sessions-for-open"
|
||||
|
||||
if(@props.active)
|
||||
className = className + " active"
|
||||
|
||||
firstTime = null
|
||||
if results.length == 0
|
||||
if @state.searching
|
||||
results = `<tr key="single"><td colSpan="3" className="none-found">... Searching ...</td></tr>`
|
||||
else
|
||||
# help = @help()
|
||||
results = `<tr key="single"><td colSpan="3" className="none-found">None Found</td></tr>`
|
||||
|
||||
if @state.end && results.length > 5
|
||||
results.push(`<tr><td colSpan="3" className="end-of-results">End of Search Results<div className="spacer"></div></td></tr>`)
|
||||
help = @help()
|
||||
|
||||
refreshButtonClasses = "button-grey btn-refresh"
|
||||
|
||||
if @state.searching
|
||||
refreshButtonClasses = refreshButtonClasses += " disabled"
|
||||
|
||||
|
||||
`<div className={className}>
|
||||
<div className="content-wrapper">
|
||||
<div id="sessions-active" className="session-container">
|
||||
<div className="header-zone">
|
||||
<h2>sessions for me</h2>
|
||||
|
||||
|
||||
<div className="refresh-btn">
|
||||
<a href="/client#/findSession" style={{textDecoration:'none'}} disabled={this.state.searching}
|
||||
className={refreshButtonClasses} onClick={this.refresh.bind(this)}>REFRESH<span class="extra"></span></a>
|
||||
</div>
|
||||
<div className="search-box">
|
||||
<input className="session-keyword-srch" type="text" name="search"
|
||||
placeholder="Search by Keyword"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
|
||||
<div className="findsession-container">
|
||||
<table id="sessions-active" className="findsession-table" cellspacing="0"
|
||||
cellpadding="0" border="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left" width="40%">SESSION</th>
|
||||
<th align="left" width="45%">MUSICIANS</th>
|
||||
<th align="left" width="10%" style={{textAlign:'center'}}>ACTIONS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{results}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{help}
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
|
||||
query: () ->
|
||||
|
||||
$root = $(this.getDOMNode())
|
||||
keyword = $root.find('input.session-keyword-srch').val()
|
||||
if keyword == ''
|
||||
keyword = undefined
|
||||
query =
|
||||
keyword: keyword
|
||||
|
||||
query
|
||||
|
||||
componentDidMount: () ->
|
||||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@logger = context.JK.logger
|
||||
|
||||
|
||||
componentDidUpdate: (prevProps, prevState) ->
|
||||
|
||||
if !@props.screenActive && prevProps.screenActive
|
||||
@searched_ever = false
|
||||
|
||||
if @props.screenActive && @props.active && !@searched_ever
|
||||
SessionsActions.updateSessions.trigger(@props.mode)
|
||||
@searched_ever = true
|
||||
|
||||
#if @props.active && !prevProps.active && !@searched_ever
|
||||
|
||||
$root = $(this.getDOMNode())
|
||||
$scroller = $root
|
||||
|
||||
if !@registeredInfiniteScroll
|
||||
@registerInfiniteScroll($scroller)
|
||||
|
||||
registerInfiniteScroll: ($scroller) ->
|
||||
@registeredInfiniteScroll = true
|
||||
|
||||
$scroller.off('scroll')
|
||||
$scroller.on('scroll', () =>
|
||||
|
||||
# be sure to not fire off many refreshes when user hits the bottom
|
||||
return if @state.searching
|
||||
|
||||
return if @state.end
|
||||
|
||||
if $scroller.scrollTop() + $scroller.innerHeight() + 400 >= $scroller[0].scrollHeight
|
||||
SessionsActions.updateSessions.trigger(@props.mode, @query())
|
||||
)
|
||||
|
||||
inviteFriends:() ->
|
||||
JK.InvitationDialogInstance.showEmailDialog();
|
||||
|
||||
onAppInit: (@app) ->
|
||||
return
|
||||
|
||||
onSessionsChanged: (sessionsChanged) ->
|
||||
if sessionsChanged.type == @props.mode
|
||||
@setState(sessionsChanged)
|
||||
|
||||
})
|
||||
|
|
@ -1,14 +1,24 @@
|
|||
context = window
|
||||
rest = window.JK.Rest()
|
||||
logger = context.JK.logger
|
||||
EVENTS = context.JK.EVENTS
|
||||
SessionsActions = context.SessionsActions
|
||||
AppStore = context.AppStore
|
||||
MAX_MINUTES_SHOW_START = 15
|
||||
|
||||
@FindSessionRow = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(AppStore, "onAppInit")]
|
||||
|
||||
ui: null
|
||||
|
||||
getInitialState: () ->
|
||||
{rsvpToggle: false, openSlotToggle: false}
|
||||
|
||||
createInstrument: (participant) ->
|
||||
|
||||
instruments = []
|
||||
existingTracks = []
|
||||
logger.debug("Find:Finding instruments. Participant tracks:", participant.tracks)
|
||||
for track in participant.tracks
|
||||
|
||||
if existingTracks.indexOf(track.instrument_id) < 0
|
||||
|
|
@ -22,31 +32,10 @@ logger = context.JK.logger
|
|||
createInSessionUser: (participant) ->
|
||||
|
||||
instruments = @createInstrument(participant)
|
||||
id = participant.user.id;
|
||||
name = participant.user.name;
|
||||
userId = id
|
||||
avatar_url = context.JK.resolveAvatarUrl(participant.user.photo_url)
|
||||
profile_url = "/client#/profile/" + id
|
||||
musician_name = name
|
||||
more_link = ''
|
||||
|
||||
`<tr>
|
||||
<td width="24">
|
||||
<a user-id={userId} hoveraction="musician" href={profile_url} className="avatar-tiny">
|
||||
<img src={avatar_url} />
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a user-id={userId} hoveraction="musician" href={profile_url}>{musician_name}</a>
|
||||
</td>
|
||||
<td>
|
||||
<div className="instruments nowrap">{instruments}</div>
|
||||
</td>
|
||||
<td>{more_link} </td>
|
||||
</tr>`
|
||||
`<HoverUser more={null} user={participant.user} instruments={instruments} />`
|
||||
|
||||
|
||||
createOpenSlot:(slot) ->
|
||||
createOpenSlot:(slot, isLast) ->
|
||||
|
||||
inst = context.JK.getInstrumentIcon24(slot.instrument_id);
|
||||
|
||||
|
|
@ -55,9 +44,20 @@ logger = context.JK.logger
|
|||
# this is to allow unstructured RSVPs to not specify proficiency_desc
|
||||
proficiency_desc = "Any Skill Level"
|
||||
|
||||
moreLinkHtml = '';
|
||||
toggle = @state.openSlotToggle
|
||||
|
||||
if isLast
|
||||
moreLinkHtml = `<span><a className="slots more">more</a><a className="details-arrow arrow-down-orange"></a></span>`
|
||||
remainingStyles = {}
|
||||
text = null
|
||||
computedClass = "details-arrow"
|
||||
if toggle
|
||||
text = 'less'
|
||||
computedClass += " arrow-up-orange"
|
||||
else
|
||||
text = 'more'
|
||||
computedClass += " arrow-down-orange"
|
||||
|
||||
moreLinkHtml = `<td><span><a onClick={this.toggleOpenSlot.bind(this)} className="rsvps more">{text}</a><a className={computedClass}></a></span></td>`
|
||||
|
||||
instrument_url = inst
|
||||
instrument = slot.description
|
||||
|
|
@ -65,9 +65,9 @@ logger = context.JK.logger
|
|||
more_link = moreLinkHtml
|
||||
|
||||
|
||||
`<tr>
|
||||
`<tr key={slot.id}>
|
||||
<td width="24">
|
||||
<img src="{instrument_url}" />
|
||||
<img src={instrument_url} />
|
||||
</td>
|
||||
<td>
|
||||
<div className="instruments nowrap">{instrument} ({proficiency})</div>
|
||||
|
|
@ -86,31 +86,23 @@ logger = context.JK.logger
|
|||
|
||||
moreLinkHtml = '';
|
||||
if isLast
|
||||
moreLinkHtml = `<span><a class="rsvps more">more</a><a className="details-arrow arrow-down-orange"></a></span>`
|
||||
# false means hide, true means show
|
||||
toggle = @state.rsvpToggle
|
||||
|
||||
#instruments = @createInstrument(user)
|
||||
id = user.id;
|
||||
name = user.name;
|
||||
userId = id
|
||||
avatar_url = context.JK.resolveAvatarUrl(user.photo_url)
|
||||
profile_url = "/client#/profile/" + id
|
||||
musician_name = name
|
||||
more_link = ''
|
||||
remainingStyles = {}
|
||||
text = null
|
||||
computedClass = "details-arrow"
|
||||
if toggle
|
||||
text = 'less'
|
||||
computedClass += " arrow-up-orange"
|
||||
else
|
||||
text = 'more'
|
||||
computedClass += " arrow-down-orange"
|
||||
|
||||
`<tr>
|
||||
<td width="24">
|
||||
<a user-id={userId} hoveraction="musician" href={profile_url} className="avatar-tiny">
|
||||
<img src={avatar_url} />
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a user-id={userId} hoveraction="musician" href={profile_url}>{musician_name}</a>
|
||||
</td>
|
||||
<td>
|
||||
<div className="instruments nowrap">{instruments}</div>
|
||||
</td>
|
||||
<td>{more_link} </td>
|
||||
</tr>`
|
||||
moreLinkHtml = `<td><span><a onClick={this.toggleRsvp.bind(this)} className="rsvps more">{text}</a><a className={computedClass}></a></span></td>`
|
||||
|
||||
|
||||
`<HoverUser user={user} instruments={instruments} more={moreLinkHtml} />`
|
||||
|
||||
|
||||
|
||||
|
|
@ -118,12 +110,17 @@ logger = context.JK.logger
|
|||
inSessionUsers = []
|
||||
|
||||
result = []
|
||||
console.log("render active", session)
|
||||
if session.active_music_session && session.active_music_session.participants && session.active_music_session.participants.length > 0
|
||||
for participant in session.active_music_session.participants
|
||||
inSessionUsers.push(participant.user.id);
|
||||
result.push(@createInSessionUser(participant))
|
||||
|
||||
if result.length == 0
|
||||
result = `<span>Abandoned</span>`
|
||||
else
|
||||
result = `<table className="musicians musicians-category" cellpadding="0" cellspacing="0" width="100%">
|
||||
{result}
|
||||
</table>`
|
||||
return [result, inSessionUsers]
|
||||
|
||||
|
||||
|
|
@ -139,8 +136,12 @@ logger = context.JK.logger
|
|||
last = session.approved_rsvps.slice(3)
|
||||
|
||||
for approved_rsvp in first
|
||||
firstResults.push(@createRsvpUser(approved_rsvp, session, approvedRsvpCount > 3 && i == 2))
|
||||
if approved_rsvp.id == session.user_id
|
||||
continue
|
||||
firstResults.push(@createRsvpUser(approved_rsvp, session, approvedRsvpCount > 3 && i == 0))
|
||||
for approved_rsvp in last
|
||||
if approved_rsvp.id == session.user_id
|
||||
continue
|
||||
lastResults.push(@createRsvpUser(approved_rsvp, session, false))
|
||||
|
||||
[firstResults, lastResults]
|
||||
|
|
@ -155,48 +156,248 @@ logger = context.JK.logger
|
|||
if session['is_unstructured_rsvp?']
|
||||
firstResults.push(@createOpenSlot({description: 'Any Instrument'}))
|
||||
|
||||
i = 0
|
||||
if session.open_slots
|
||||
|
||||
openSlotCount = session.open_slots.length
|
||||
for openSlot in session.open_slots
|
||||
if i < 3
|
||||
firstResults.push(@createOpenSlot(openSlot, openSlotCount > 3 && i == 2))
|
||||
else
|
||||
remainingResults.push(@createOpenSlot(openSlot, false))
|
||||
i++
|
||||
|
||||
|
||||
return [firstResults, remainingResults]
|
||||
|
||||
showJoinLink: (session, inSessionUsers) ->
|
||||
showJoinLink = session.musician_access
|
||||
if session.approved_rsvps
|
||||
for approved_rsvps in session.approved_rsvps
|
||||
# do not show the user in this section if he is already in the session
|
||||
if $.inArray(approved_rsvps.id, inSessionUsers) == -1
|
||||
if approved_rsvps.id == context.JK.currentUserId
|
||||
showJoinLink = true
|
||||
else
|
||||
showJoinLink = true
|
||||
joinLink: (session, inSessionUsers) ->
|
||||
#showJoinLink = session.musician_access
|
||||
#if session.approved_rsvps
|
||||
# for approved_rsvps in session.approved_rsvps
|
||||
# # do not show the user in this section if he is already in the session
|
||||
# if $.inArray(approved_rsvps.id, inSessionUsers) == -1
|
||||
# if approved_rsvps.id == context.JK.currentUserId
|
||||
# showJoinLink = true
|
||||
# else
|
||||
# showJoinLink = true
|
||||
|
||||
showJoinLink
|
||||
|
||||
rsvps: (session, rsvp_musicians_first_3, rsvp_musicians_remaining) ->
|
||||
|
||||
if session.create_type == 'quick-start' || !rsvp_musicians_first_3 || rsvp_musicians_first_3.length == 0
|
||||
if @props.mode == 'upcoming'
|
||||
return null
|
||||
|
||||
` <tr>
|
||||
<td>RSVPs:</td>
|
||||
joinText = 'Join'
|
||||
if session.highlight
|
||||
highlight = session.highlight
|
||||
if highlight.updated
|
||||
joinText = 'Ready!'
|
||||
|
||||
`<div className="center">
|
||||
<a className="join-link" onClick={this.joinLinkClicked.bind(this, session)}>
|
||||
<div className="join-icon"></div>
|
||||
</a>
|
||||
<div className="join-link-text">{joinText}</div>
|
||||
</div>`
|
||||
|
||||
|
||||
rsvpLink: (session) ->
|
||||
|
||||
pendingRsvpId = null
|
||||
approvedRsvpId = null
|
||||
hasInvitation = false
|
||||
|
||||
for pending_rsvp_request in session.pending_rsvp_requests
|
||||
if pending_rsvp_request.user_id == context.JK.currentUserId
|
||||
pendingRsvpId = pending_rsvp_request.id
|
||||
break
|
||||
|
||||
for approved_rsvp in session.approved_rsvps
|
||||
if approved_rsvp.id == context.JK.currentUserId
|
||||
approvedRsvpId = approved_rsvp.rsvp_request_id
|
||||
break
|
||||
|
||||
if session.invitations
|
||||
for pending_invitation in session.invitations
|
||||
if context.JK.currentUserId == pending_invitation.receiver_id
|
||||
hasInvitation = true
|
||||
break
|
||||
|
||||
|
||||
errorMsg = null
|
||||
error = false
|
||||
|
||||
if error
|
||||
errorMsg = `<span className="rsvp-msg" style="display:none;">You cannot RSVP to this session.</span>`
|
||||
|
||||
# if this is your own session, let you start it immediately
|
||||
if context.JK.currentUserId == session.user_id
|
||||
result = `<div className="center"><span className="text"><a onClick={this.startSessionNow.bind(this, session)} className="start" style={{color: '#fc0'}}>Start session now?</a><br/><br/>This is your session.</span></div>`
|
||||
return result
|
||||
|
||||
# if you are approved RSVP person, let you cancel it
|
||||
if approvedRsvpId
|
||||
|
||||
if session.scheduled_start && @showStartSessionButton(session.scheduled_start)
|
||||
# give user both option to start session, and also cancel RSVP
|
||||
result = `<div className="center"><span className="text"><a onClick={this.startSessionNow.bind(this, session)} className="start">Start session now?</a> | <a onClick={this.cancelRsvpClicked.bind(this, session, approvedRsvpId)} className="cancel">Cancel RSVP</a></span></div>`
|
||||
return result
|
||||
else
|
||||
# user can just cancel their RSVP
|
||||
result = `<div className="center"><span className="text"><a onClick={this.cancelRsvpClicked.bind(this, session, approvedRsvpId)} className="cancel">Cancel RSVP</a></span></div>`
|
||||
return result
|
||||
|
||||
else if hasInvitation
|
||||
if session.scheduled_start && @showStartSessionButton(session.scheduled_start)
|
||||
# give user both option to start session, and also cancel RSVP
|
||||
result = `<div className="center"><span className="text"><a onClick={this.startSessionNow.bind(this, session)} className="start">Start session now?</a> | You have an invite to this session.<br/><br/>You can join it when it starts.</span></div>`
|
||||
return result
|
||||
else
|
||||
# user can just cancel their RSVP
|
||||
result = `<div className="center"><span className="text">You have an invite to this session.<br/><br/>You can join it when it starts.</span></div>`
|
||||
return result
|
||||
|
||||
else if pendingRsvpId
|
||||
result = `<div className="center"><span className="text"><a onClick={this.cancelRsvpClicked.bind(this, session, pendingRsvpId)} className="cancel">Cancel RSVP</a></span></div>`
|
||||
return result
|
||||
|
||||
else if !session['is_unstructured_rsvp?'] && session.open_slots.length == 0
|
||||
result = `<div className="center"><span className="text">No more open positions.</span></div>`
|
||||
return result
|
||||
|
||||
|
||||
else if !session.open_rsvps && !hasInvitation
|
||||
result = `<div className="center"><span className="text">You need an invitation to RSVP to this session.</span></div>`
|
||||
return result
|
||||
|
||||
|
||||
`<div className="center">
|
||||
{errorMsg}
|
||||
<a className="rsvp-link" onClick={this.rsvpLinkClicked.bind(this, session)}>
|
||||
<div className="rsvp-icon"></div>
|
||||
</a>
|
||||
<div className="rsvp-link-text">RSVP</div>
|
||||
</div>`
|
||||
|
||||
openSlots: (session, open_slots_first_3, open_slots_remaining) ->
|
||||
|
||||
# false means hide, true means show
|
||||
openSlotToggle = @state.openSlotToggle
|
||||
|
||||
remainingStyles = {}
|
||||
if openSlotToggle
|
||||
remainingStyles.display = 'block'
|
||||
else
|
||||
remainingStyles.display = 'none'
|
||||
`<tr className="musicians-detail">
|
||||
<td className="musicians-header"><span>Still Needed:</span></td>
|
||||
<td>
|
||||
<table className="musicians" cellpadding="0" cellspacing="0" width="100%">
|
||||
{rsvp_musicians_first_3}
|
||||
<table className="musicians musicians-category" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
{open_slots_first_3}
|
||||
</tbody>
|
||||
</table>
|
||||
<div style={{display:'none'}}>
|
||||
<table className="musicians" cellpadding="0" cellspacing="0" width="100%">
|
||||
{rsvp_musicians_remaining}
|
||||
<div style={remainingStyles}>
|
||||
<table className="musicians remaining" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
{open_slots_remaining}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>`
|
||||
|
||||
rsvps: (session, rsvp_musicians_first_3, rsvp_musicians_remaining, open_slots_first_3) ->
|
||||
|
||||
if session.create_type == 'quick-start' || ((!rsvp_musicians_first_3 || rsvp_musicians_first_3.length == 0) && (!open_slots_first_3 || open_slots_first_3.length == 0))
|
||||
return null
|
||||
|
||||
# if no rsvps yet some open slots
|
||||
if (!rsvp_musicians_first_3 || rsvp_musicians_first_3.length == 0) && (open_slots_first_3 && open_slots_first_3.length > 0)
|
||||
return `<tr className="musicians-detail">
|
||||
<td className="musicians-header"><span>RSVPs:</span></td>
|
||||
<td>
|
||||
<div className="none-yet">
|
||||
None yet
|
||||
</div>
|
||||
</td>
|
||||
</tr>`
|
||||
|
||||
|
||||
# false means hide, true means show
|
||||
rsvpToggle = @state.rsvpToggle
|
||||
|
||||
remainingStyles = {}
|
||||
if rsvpToggle
|
||||
remainingStyles.display = 'block'
|
||||
else
|
||||
remainingStyles.display = 'none'
|
||||
`<tr className="musicians-detail">
|
||||
<td className="musicians-header"><span>RSVPs:</span></td>
|
||||
<td>
|
||||
<table className="musicians musicians-category" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
{rsvp_musicians_first_3}
|
||||
</tbody>
|
||||
</table>
|
||||
<div style={remainingStyles}>
|
||||
<table className="musicians" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
{rsvp_musicians_remaining}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>`
|
||||
|
||||
componentDidMount: () ->
|
||||
@ui = new context.JK.UIHelper(AppStore.app)
|
||||
|
||||
ensuredCallback: (sessionId) ->
|
||||
context.JK.SessionUtils.joinSession(sessionId)
|
||||
|
||||
joinLinkClicked: (session) ->
|
||||
context.JK.SessionUtils.ensureValidClient(@app, context.JK.GearUtils, @ensuredCallback.bind(this, session.id))
|
||||
|
||||
rsvpLinkClicked: (session) ->
|
||||
@ui.launchRsvpSubmitDialog(session.id)
|
||||
.one(EVENTS.RSVP_SUBMITTED, () -> SessionsActions.updateSession.trigger(session.id))
|
||||
.one(EVENTS.DIALOG_CLOSED, () ->
|
||||
$(this).unbind(EVENTS.RSVP_SUBMITTED);
|
||||
)
|
||||
return false
|
||||
|
||||
toggleRsvp: () ->
|
||||
@setState(rsvpToggle: !@state.rsvpToggle)
|
||||
|
||||
toggleOpenSlot: (sessionId) ->
|
||||
@setState(openSlotToggle: !@state.openSlotToggle)
|
||||
|
||||
startSessionNow: (session) ->
|
||||
@ui.launchSessionStartDialog(session)
|
||||
|
||||
showStartSessionButton: (scheduledStart) ->
|
||||
now = new Date()
|
||||
scheduledDate = new Date(scheduledStart)
|
||||
minutesFromStart = (scheduledDate.getTime() - now.getTime()) / (1000 * 60)
|
||||
minutesFromStart <= MAX_MINUTES_SHOW_START
|
||||
|
||||
cancelRsvpClicked: (session, approvedRsvpId) ->
|
||||
@ui.launchRsvpCancelDialog(session.id, approvedRsvpId)
|
||||
.one(EVENTS.RSVP_CANCELED, () -> SessionsActions.updateSession.trigger(session.id))
|
||||
.one(EVENTS.DIALOG_CLOSED, () ->
|
||||
$(this).unbind(EVENTS.RSVP_CANCELED);
|
||||
)
|
||||
return false
|
||||
|
||||
|
||||
inSessionMusicians: (in_session_musicians) ->
|
||||
if @props.mode == 'upcoming'
|
||||
return null
|
||||
|
||||
`<tr className="musicians-detail">
|
||||
<td className="musicians-header"><span>In Session:</span></td>
|
||||
<td>
|
||||
{in_session_musicians}
|
||||
</td>
|
||||
</tr>`
|
||||
render: () ->
|
||||
|
||||
session = @props.session
|
||||
|
|
@ -209,12 +410,29 @@ logger = context.JK.logger
|
|||
[in_session_musicians, inSessionUsers] = @inSessionUsersHtml(session)
|
||||
[rsvp_musicians_first_3, rsvp_musicians_remaining] = @createRsvpUsers(session)
|
||||
[open_slots_first_3, open_slots_remaining] = @createOpenSlots(session)
|
||||
showJoinLink = @showJoinLink(session, inSessionUsers)
|
||||
rsvps = @rsvps(session, rsvp_musicians_first_3, rsvp_musicians_remaining, open_slots_first_3)
|
||||
|
||||
|
||||
joinLink = @joinLink(session, inSessionUsers)
|
||||
showListenLink = session.fan_access && session.active_music_session && session.active_music_session.mount
|
||||
join_link_display_style = {display: "none"}
|
||||
showListenLink = false # for now... XXX
|
||||
|
||||
openSlots = null
|
||||
|
||||
scheduled_start = null
|
||||
rsvpLink = null
|
||||
if @props.mode == 'upcoming'
|
||||
|
||||
openSlots = @openSlots(session, open_slots_first_3, open_slots_remaining)
|
||||
|
||||
scheduled_start = ` <tr>
|
||||
<td colspan="2">{session.pretty_scheduled_start_with_timezone}</td>
|
||||
</tr>`
|
||||
|
||||
rsvpLink = @rsvpLink(session)
|
||||
|
||||
|
||||
listen_link_display_style = {display: "none"}
|
||||
if showJoinLink
|
||||
join_link_display_style = {display: "block"}
|
||||
if showListenLink
|
||||
listen_link_display_style = {display: "inline-block"}
|
||||
listen_link_text = ''
|
||||
|
|
@ -226,32 +444,42 @@ logger = context.JK.logger
|
|||
else
|
||||
listen_link_text = '';
|
||||
|
||||
rsvps = @rsvps(rsvp_musicians_first_3, rsvp_musicians_remaining)
|
||||
remark = null
|
||||
if session.highlight
|
||||
highlight = session.highlight
|
||||
if highlight.new
|
||||
remark = `<div className="highlight new">NEW!</div>`
|
||||
|
||||
|
||||
inSessionMusicians = @inSessionMusicians(in_session_musicians)
|
||||
|
||||
|
||||
`<tr data-session-id={id} className="found-session">
|
||||
<td width="40%" className="session-cell">
|
||||
{remark}
|
||||
<table className="musician-groups" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<td className="bold"><a className="session-name" href={"/sessions/" + id} rel="external">{name}</a></td>
|
||||
<td align="right" width="75" className="session-genre">{genres}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" className="session-description">{description}</td>
|
||||
</tr>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="bold"><a className="session-name" href={"/sessions/" + id} rel="external">{name}</a></td>
|
||||
<td align="right" width="75" className="session-genre">{genres}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" className="session-description">{description}</td>
|
||||
</tr>
|
||||
|
||||
{scheduled_start}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="spacer"></div>
|
||||
</td>
|
||||
<td width="45%" className="session-musicians">
|
||||
<table className="musicians" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td>In Session:</td>
|
||||
<td>
|
||||
<table className="musicians" cellpadding="0" cellspacing="0" width="100%">
|
||||
{in_session_musicians}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tbody>
|
||||
{inSessionMusicians}
|
||||
{rsvps}
|
||||
{openSlots}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="spacer"></div>
|
||||
</td>
|
||||
|
|
@ -263,12 +491,8 @@ logger = context.JK.logger
|
|||
<br/>
|
||||
<span className="listen-link-details"><span className="listen-link-text">{listen_link_text}</span><a href="#" className="listen-detail-hover">?</a></span>
|
||||
</div>
|
||||
<div className="center">
|
||||
<a className="join-link" style={join_link_display_style}>
|
||||
<div className="join-icon"></div>
|
||||
</a>
|
||||
<span className="join-link-text">Join</span>
|
||||
</div>
|
||||
{joinLink}
|
||||
{rsvpLink}
|
||||
<div className="spacer"></div>
|
||||
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
context = window
|
||||
MIX_MODES = context.JK.MIX_MODES
|
||||
|
||||
SessionsActions = @SessionsActions
|
||||
|
||||
@FindSessionScreen = React.createClass({
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ MIX_MODES = context.JK.MIX_MODES
|
|||
instrument_logo_map: context.JK.getInstrumentIconMap24()
|
||||
|
||||
getInitialState: () ->
|
||||
{activeTab: 'friends', search: '', type: 'user-input'}
|
||||
{activeTab: '', search: '', type: 'user-input', screenActive: false}
|
||||
|
||||
|
||||
generateProperties: (tab) ->
|
||||
|
|
@ -28,33 +29,35 @@ MIX_MODES = context.JK.MIX_MODES
|
|||
|
||||
classNames(classes)
|
||||
|
||||
tabActivate: (tab) ->
|
||||
@setState({activeTab: tab})
|
||||
|
||||
render: () ->
|
||||
|
||||
friendTabClasses = @generateTabClasses('friends')
|
||||
publicTabClasses = @generateTabClasses('public')
|
||||
scheduledTabClasses = @generateTabClasses('scheduled')
|
||||
myTabClasses = @generateTabClasses('my')
|
||||
openTabClasses = @generateTabClasses('open')
|
||||
upcomingTabClasses = @generateTabClasses('upcoming')
|
||||
|
||||
friendProperties = @generateProperties('friends')
|
||||
publicProperties = @generateProperties('public')
|
||||
scheduledProperties = @generateProperties('scheduled')
|
||||
myProperties = @generateProperties('my')
|
||||
openProperties = @generateProperties('open')
|
||||
upcomingProperties = @generateProperties('upcoming')
|
||||
|
||||
search = ''
|
||||
|
||||
`<div className="">
|
||||
<div className="">
|
||||
`<div className="FindSessionScreen">
|
||||
<form id="find-session-form">
|
||||
<div className="session-filter">
|
||||
<div style={{minWidth:'770px'}}>
|
||||
<div className="tabs">
|
||||
<a className={friendTabClasses}>
|
||||
Friends
|
||||
<a className={myTabClasses} onClick={this.tabActivate.bind(this, 'my')}>
|
||||
For Me
|
||||
</a>
|
||||
|
||||
<a className={publicTabClasses}>
|
||||
Public
|
||||
<a className={openTabClasses} onClick={this.tabActivate.bind(this, 'open')}>
|
||||
Open Jams
|
||||
</a>
|
||||
|
||||
<a className={scheduledTabClasses}>
|
||||
<a className={upcomingTabClasses} onClick={this.tabActivate.bind(this, 'upcoming')}>
|
||||
Upcoming
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -62,23 +65,33 @@ MIX_MODES = context.JK.MIX_MODES
|
|||
</div>
|
||||
</form>
|
||||
|
||||
<FindSessionFriends active={friendProperties.active} />
|
||||
</div>
|
||||
</div>`
|
||||
<FindSessionOpen mode='my' active={myProperties.active} screenActive={this.state.screenActive}/>
|
||||
<FindSessionOpen mode='open' active={openProperties.active} screenActive={this.state.screenActive} />
|
||||
<FindSessionOpen mode='upcoming' active={upcomingProperties.active} screenActive={this.state.screenActive} />
|
||||
</div>`
|
||||
|
||||
|
||||
|
||||
componentDidMount: () ->
|
||||
return
|
||||
|
||||
componentDidUpdate: () ->
|
||||
componentDidUpdate: (prevProps, prevState) ->
|
||||
return
|
||||
|
||||
beforeShow: () ->
|
||||
return
|
||||
|
||||
afterShow: () ->
|
||||
return
|
||||
SessionsActions.watching.trigger(true)
|
||||
|
||||
if @state.activeTab == ''
|
||||
@setState({activeTab: 'my'})
|
||||
|
||||
@setState({screenActive:true})
|
||||
beforeHide: () ->
|
||||
SessionsActions.watching.trigger(false)
|
||||
SessionsActions.resetSessions.trigger()
|
||||
@setState({screenActive:false})
|
||||
|
||||
onAppInit: (@app) ->
|
||||
@EVENTS = context.JK.EVENTS
|
||||
|
|
@ -88,6 +101,7 @@ MIX_MODES = context.JK.MIX_MODES
|
|||
screenBindings =
|
||||
'beforeShow': @beforeShow
|
||||
'afterShow': @afterShow
|
||||
'beforeHide': @beforeHide
|
||||
|
||||
@app.bindScreen('findSession', screenBindings)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
context = window
|
||||
rest = window.JK.Rest()
|
||||
logger = context.JK.logger
|
||||
EVENTS = context.JK.EVENTS
|
||||
SessionsActions = context.SessionsActions
|
||||
AppStore = context.AppStore
|
||||
MAX_MINUTES_SHOW_START = 15
|
||||
|
||||
@HoverUser = React.createClass({
|
||||
|
||||
render: () ->
|
||||
|
||||
user = this.props.user
|
||||
|
||||
userId = user.id
|
||||
name = user.name
|
||||
avatar_url = context.JK.resolveAvatarUrl(user.photo_url)
|
||||
profile_url = "/client#/profile/" + userId
|
||||
musician_name = name
|
||||
|
||||
`<tr key={userId} >
|
||||
<td width="24">
|
||||
<a user-id={userId} data-hoveraction="musician" href={profile_url} className="avatar-tiny">
|
||||
<img src={avatar_url} />
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a user-id={userId} data-hoveraction="musician" href={profile_url}>{musician_name}</a>
|
||||
</td>
|
||||
<td>
|
||||
<div className="instruments nowrap">{this.props.instruments}</div>
|
||||
</td>
|
||||
{this.props.more}
|
||||
</tr>`
|
||||
|
||||
componentDidMount: () ->
|
||||
$root = $(this.getDOMNode())
|
||||
context.JK.bindHoverEvents($root, "data-hoveraction")
|
||||
})
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
context = window
|
||||
|
||||
@FriendActions = Reflux.createActions({
|
||||
updateFriends: {}
|
||||
})
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
context = window
|
||||
|
||||
@SessionsActions = Reflux.createActions({
|
||||
updateSession: {}
|
||||
updateSessions: {}
|
||||
resetSessions: {}
|
||||
clearSessions: {}
|
||||
watching: {}
|
||||
})
|
||||
|
|
@ -6,9 +6,12 @@ logger = context.JK.logger
|
|||
{
|
||||
listenables: @AppActions
|
||||
|
||||
app: null
|
||||
onAppInit: (app) ->
|
||||
@app = app
|
||||
@trigger(app)
|
||||
|
||||
|
||||
onOpenExternalUrl: (href) ->
|
||||
|
||||
logger.debug("opening external url #{href}")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
logger = context.JK.logger
|
||||
rest = context.JK.Rest()
|
||||
FriendActions = @FriendActions
|
||||
|
||||
@FriendStore = Reflux.createStore(
|
||||
{
|
||||
listenables: FriendActions
|
||||
|
||||
friends: []
|
||||
|
||||
init: ->
|
||||
# Register with the app store to get @app
|
||||
this.listenTo(context.AppStore, this.onAppInit)
|
||||
|
||||
onAppInit: (@app) ->
|
||||
return
|
||||
|
||||
updateFriends: (friends) ->
|
||||
@friends = friends
|
||||
|
||||
issueChange: (type) ->
|
||||
@trigger({friends: @friends})
|
||||
|
||||
isFriend: (userId) ->
|
||||
|
||||
found = false
|
||||
for friend in @friends
|
||||
if friend.id == userId
|
||||
found = true
|
||||
break
|
||||
found
|
||||
}
|
||||
)
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
logger = context.JK.logger
|
||||
rest = context.JK.Rest()
|
||||
SessionActions = @SessionActions
|
||||
|
||||
@SessionsStore = Reflux.createStore(
|
||||
{
|
||||
listenables: SessionsActions
|
||||
|
||||
my: {sessions: [], currentPage: 0, next: null, searching: false, count: 0}
|
||||
open: {sessions: [], currentPage: 0, next: null, searching: false, count: 0}
|
||||
upcoming: {sessions: [], currentPage: 0, next: null, searching: false, count: 0}
|
||||
|
||||
highlight: null
|
||||
|
||||
LIMITS: {my: 50, open: 50, upcoming: 20}
|
||||
|
||||
TYPE_MY: 'my'
|
||||
TYPE_OPEN: 'open'
|
||||
TYPE_UPCOMING: 'upcoming'
|
||||
|
||||
# if the Find Session screen isn't active, don't 'watch' automatically
|
||||
watchingState: false
|
||||
|
||||
init: ->
|
||||
# Register with the app store to get @app
|
||||
this.listenTo(context.AppStore, this.onAppInit)
|
||||
|
||||
onAppInit: (@app) ->
|
||||
return
|
||||
|
||||
defaultQuery: (extra, type) ->
|
||||
query =
|
||||
limit: @LIMITS[type],
|
||||
offset: this[type].currentPage * @LIMITS[type]
|
||||
|
||||
$.extend(query, extra)
|
||||
|
||||
updateSessionState:(session, type) ->
|
||||
state = this[type]
|
||||
|
||||
# so callers can realize this is a pinpointed session update
|
||||
session.highlight = {new: false, updated: false}
|
||||
@highlight = session
|
||||
|
||||
|
||||
foundIndex = -1
|
||||
|
||||
console.log("STATE", state)
|
||||
if state.sessions.length > 0
|
||||
for x in [0..state.sessions.length - 1]
|
||||
if state.sessions[x].id == session.id
|
||||
foundIndex = x
|
||||
break
|
||||
|
||||
# session did not exist already. Add it to front of list because that's where interesting stuff should be?
|
||||
if foundIndex == -1
|
||||
session.highlight.new = true
|
||||
console.log("SessionStore.updateSession: adding a new one")
|
||||
state.sessions.unshift(session)
|
||||
else
|
||||
session.highlight.updated = true
|
||||
console.log("SessionStore.updateSession: updating existing")
|
||||
state.sessions[x] = session
|
||||
|
||||
|
||||
updateSession: (sessionId) ->
|
||||
if !@watchingState
|
||||
return
|
||||
|
||||
rest.getSessionHistory(sessionId)
|
||||
.done((response) =>
|
||||
determined_type = null
|
||||
if response.active_music_session
|
||||
if response.can_join || context.FriendStore.isFriend(response.user_id)
|
||||
determined_type = @TYPE_MY
|
||||
else
|
||||
determined_type = @TYPE_OPEN
|
||||
else
|
||||
determined_type = @TYPE_UPCOMING
|
||||
|
||||
@updateSessionState(response, determined_type)
|
||||
@issueChange(determined_type)
|
||||
)
|
||||
.fail((jqXHR) =>
|
||||
@app.notifyServerError jqXHR, 'SessionsStore: Unable to fetch session information'
|
||||
)
|
||||
|
||||
resetSessions:() ->
|
||||
@my.sessions = []
|
||||
@my.currentPage = 0
|
||||
@my.end = false
|
||||
@open.sessions = []
|
||||
@open.currentPage = 0
|
||||
@open.end = false
|
||||
@upcoming.sessions = []
|
||||
@upcoming.currentPage = 0
|
||||
@upcoming.end = false
|
||||
@issueChange(@TYPE_MY)
|
||||
@issueChange(@TYPE_OPEN)
|
||||
@issueChange(@TYPE_UPCOMING)
|
||||
|
||||
clearSessions: (type, query) ->
|
||||
this[type].sessions = []
|
||||
this[type].currentPage = 0
|
||||
this[type].end = false
|
||||
@updateSessions(type, query)
|
||||
|
||||
handleSessionResponse: (type, response) ->
|
||||
state = this[type]
|
||||
state.sessions = state.sessions.concat(response.sessions)
|
||||
state.searching = false
|
||||
state.currentPage = state.currentPage + 1
|
||||
state.first_search = false
|
||||
state.error = null
|
||||
state.end = response.sessions.length < @LIMITS[type]
|
||||
@issueChange(type)
|
||||
|
||||
handleSessionError: (type, response) ->
|
||||
#@app.notifyServerError jqXHR, 'Search Unavailable'
|
||||
state = this[type]
|
||||
state.searching = false
|
||||
state.error = jqXHR
|
||||
@issueChange(type)
|
||||
|
||||
updateSessions: (type, query) ->
|
||||
|
||||
query = @defaultQuery(query, type)
|
||||
|
||||
this[type].searching = true
|
||||
@issueChange(type)
|
||||
|
||||
if type == 'my'
|
||||
rest.findFriendSessions(query)
|
||||
.done((response) =>
|
||||
@handleSessionResponse(type, response)
|
||||
)
|
||||
.fail((jqXHR) =>
|
||||
@handleSessionError(type, jqXHR)
|
||||
)
|
||||
|
||||
else if type == 'open'
|
||||
rest.findPublicSessions(query)
|
||||
.done((response) =>
|
||||
@handleSessionResponse(type, response)
|
||||
)
|
||||
.fail((jqXHR) =>
|
||||
@handleSessionError(type, jqXHR)
|
||||
)
|
||||
else if type == 'upcoming'
|
||||
rest.findInactiveSessions(query)
|
||||
.done((response) =>
|
||||
@handleSessionResponse(type, response)
|
||||
)
|
||||
.fail((jqXHR) =>
|
||||
@handleSessionError(type, jqXHR)
|
||||
)
|
||||
|
||||
watching:(watching) ->
|
||||
@watchingState = watching
|
||||
|
||||
issueChange: (type) ->
|
||||
sessions = this[type]
|
||||
@trigger({type: type, sessions: sessions.sessions, highlight: @highlight, searching: sessions.searching, currentPage: sessions.currentPage, end: sessions.end})
|
||||
@highlight = null
|
||||
|
||||
}
|
||||
)
|
||||
|
|
@ -24,7 +24,9 @@
|
|||
band: {},
|
||||
musician_access: {},
|
||||
fans_access: {},
|
||||
open_rsvps: false
|
||||
open_rsvps: false,
|
||||
friends_can_join: false
|
||||
|
||||
};
|
||||
var friendInput = null;
|
||||
|
||||
|
|
@ -49,6 +51,7 @@
|
|||
var $selectedFilenames = null;
|
||||
var $uploadSpinner = null;
|
||||
var $quickStartSoloBtn = null;
|
||||
var $quickStartFriendsBtn = null;
|
||||
var $quickStartOpenBtn = null;
|
||||
var $startOrScheduledBtn = null;
|
||||
var $featureSessions = null;
|
||||
|
|
@ -245,6 +248,16 @@
|
|||
|
||||
logger.debug("user clicked quick start solo")
|
||||
createSessionSettings.createType = '<%= MusicSession::CREATE_TYPE_QUICK_START %>'
|
||||
createSessionSettings.friends_can_join = false
|
||||
next();
|
||||
return false;
|
||||
}
|
||||
|
||||
function clickQuickStartFriends () {
|
||||
|
||||
logger.debug("user clicked quick start solo")
|
||||
createSessionSettings.createType = '<%= MusicSession::CREATE_TYPE_QUICK_START %>'
|
||||
createSessionSettings.friends_can_join = true
|
||||
next();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -253,6 +266,7 @@
|
|||
|
||||
logger.debug("user clicked quick start public")
|
||||
createSessionSettings.createType = '<%= MusicSession::CREATE_TYPE_QUICK_PUBLIC %>'
|
||||
createSessionSettings.friends_can_join = false
|
||||
next();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -725,6 +739,10 @@
|
|||
createSessionSettings.fans_access.value = $fansAccess.val();
|
||||
createSessionSettings.fans_access.label = $fansAccess.get(0).options[$fansAccess.get(0).selectedIndex].text;
|
||||
|
||||
var $friendsCanJoin = $screen.find('#session-friends-can-join');
|
||||
createSessionSettings.friends_can_join = $friendsCanJoin.val() == 'true'
|
||||
//createSessionSettings.friends_can_join.label = $friendsCanJoin.get(0).options[$friendsCanJoin.get(0).selectedIndex].text;
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
|
|
@ -832,6 +850,7 @@
|
|||
data.timezone = createSessionSettings.timezone.value;
|
||||
data.open_rsvps = createSessionSettings.open_rsvps;
|
||||
data.create_type = createSessionSettings.createType;
|
||||
data.friends_can_join = createSessionSettings.friends_can_join;
|
||||
|
||||
data.rsvp_slots = [];
|
||||
$.each(getCreatorInstruments(), function(index, instrument) {
|
||||
|
|
@ -893,7 +912,7 @@
|
|||
joinSession(newSessionId);
|
||||
}
|
||||
else {
|
||||
app.notifyAlert("Session is successfully published.");
|
||||
app.notifyAlert("Session published! It can be now found on the Find Session screen.");
|
||||
context.location = '/client#/home';
|
||||
}
|
||||
})
|
||||
|
|
@ -1244,6 +1263,7 @@
|
|||
|
||||
context.JK.dropdown($screen.find('#session-musician-access'));
|
||||
context.JK.dropdown($screen.find('#session-fans-access'));
|
||||
context.JK.dropdown($screen.find('#session-friends-can-join'));
|
||||
context.JK.dropdown($timezoneList);
|
||||
context.JK.dropdown($recurringModeList);
|
||||
context.JK.dropdown($languageList);
|
||||
|
|
@ -1398,6 +1418,11 @@
|
|||
$('#session-fans-access-info .info-box[fans-access-type="' + $(event.target).val() + '"]').removeClass('hidden');
|
||||
}
|
||||
|
||||
function toggleFriendsCanJoinTypes(event) {
|
||||
$('#session-friends-can-join-info .info-box').addClass('hidden');
|
||||
$('#session-friends-can-join-info .info-box[friends-can-join-type="' + $(event.target).val() + '"]').removeClass('hidden');
|
||||
}
|
||||
|
||||
function selectBand() {
|
||||
var bandId = $bandList.get(0).options[$bandList.get(0).selectedIndex].value;
|
||||
if (bandId != '') {
|
||||
|
|
@ -1435,8 +1460,10 @@
|
|||
$createTypes.on("ifChanged", toggleCreateType);
|
||||
$startTimeList.on('change', function() { toggleStartTime(); });
|
||||
$policyTypes.on("ifChanged", togglePolicyTypeChanged);
|
||||
$('#session-step-4 #session-musician-access').on('change', toggleMusicianAccessTypes);
|
||||
$('#session-step-4 #session-fans-access').on('change', toggleFanAccessTypes);
|
||||
$('#session-step-5 #session-musician-access').on('change', toggleMusicianAccessTypes);
|
||||
$('#session-step-5 #session-fans-access').on('change', toggleFanAccessTypes);
|
||||
$('#session-step-5 #session-friends-can-join').on('change', toggleFriendsCanJoinTypes);
|
||||
|
||||
|
||||
$('div[layout-id="createSession"] .btn-email-invitation').click(function() {
|
||||
invitationDialog.showEmailDialog();
|
||||
|
|
@ -1457,6 +1484,7 @@
|
|||
$btnSelectFiles.on('click', toggleSelectFiles);
|
||||
|
||||
$quickStartSoloBtn.on('click', clickQuickStartSolo)
|
||||
$quickStartFriendsBtn.on('click', clickQuickStartFriends)
|
||||
$quickStartOpenBtn.on('click', clickQuickStartPublic)
|
||||
$startOrScheduledBtn.on('click', clickStartOrSchedule)
|
||||
}
|
||||
|
|
@ -1500,6 +1528,7 @@
|
|||
$noSessionFound = $screen.find("#scheduled-session-not-found");
|
||||
$sessionHeader = $screen.find('.session-header')
|
||||
$quickStartSoloBtn = $screen.find('.quick-start-solo')
|
||||
$quickStartFriendsBtn = $screen.find('.quick-start-friends')
|
||||
$quickStartOpenBtn = $screen.find('.quick-start-open')
|
||||
$startOrScheduledBtn = $screen.find('.start-or-schedule')
|
||||
$featureSessions = $screen.find('.featured-sessions tbody')
|
||||
|
|
|
|||
|
|
@ -196,6 +196,10 @@
|
|||
openJoinSessionTerms(sessionId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if it's private, yet we can see it, presumably we are friends (better there was a front-end check here)
|
||||
openJoinRequestAlert(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@
|
|||
return 0;
|
||||
});
|
||||
|
||||
context.FriendActions.updateFriends.trigger(response)
|
||||
|
||||
|
||||
$.each(response, function(index, val) {
|
||||
|
||||
var css = val.online ? '' : 'offline';
|
||||
|
|
|
|||
|
|
@ -466,12 +466,16 @@
|
|||
return css;
|
||||
}
|
||||
|
||||
context.JK.bindHoverEvents = function ($parent) {
|
||||
context.JK.bindHoverEvents = function ($parent, hoveractionAttr) {
|
||||
var timeout = 300;
|
||||
var fadeoutValue = 100;
|
||||
var sensitivity = 3;
|
||||
var interval = 500;
|
||||
|
||||
if(!hoveractionAttr) {
|
||||
hoveractionAttr = 'hoveraction'
|
||||
}
|
||||
|
||||
if (!$parent) {
|
||||
$parent = $('body');
|
||||
}
|
||||
|
|
@ -505,7 +509,7 @@
|
|||
}
|
||||
|
||||
// MUSICIAN
|
||||
$("[hoveraction='musician']", $parent).hoverIntent({
|
||||
$("[" + hoveractionAttr + "='musician']", $parent).hoverIntent({
|
||||
over: function(e) {
|
||||
var bubble = new JK.MusicianHoverBubble($(this).attr('user-id'), e.pageX, e.pageY);
|
||||
|
||||
|
|
@ -522,7 +526,7 @@
|
|||
});
|
||||
|
||||
// FAN
|
||||
$("[hoveraction='fan']", $parent).hoverIntent({
|
||||
$("[" + hoveractionAttr + "='fan']", $parent).hoverIntent({
|
||||
over: function(e) {
|
||||
var bubble = new JK.FanHoverBubble($(this).attr('user-id'), e.pageX, e.pageY);
|
||||
showBubble(bubble, $(this));
|
||||
|
|
@ -536,7 +540,7 @@
|
|||
});
|
||||
|
||||
// BAND
|
||||
$("[hoveraction='band']", $parent).hoverIntent({
|
||||
$("[" + hoveractionAttr +"='band']", $parent).hoverIntent({
|
||||
over: function(e) {
|
||||
var bubble = new JK.BandHoverBubble($(this).attr('band-id'), e.pageX, e.pageY);
|
||||
showBubble(bubble, $(this));
|
||||
|
|
@ -550,7 +554,7 @@
|
|||
});
|
||||
|
||||
// SESSION
|
||||
$("[hoveraction='session']", $parent).hoverIntent({
|
||||
$("[" + hoveractionAttr + "='session']", $parent).hoverIntent({
|
||||
over: function(e) {
|
||||
var bubble = new JK.SessionHoverBubble($(this).attr('session-id'), e.pageX, e.pageY);
|
||||
showBubble(bubble, $(this));
|
||||
|
|
@ -564,7 +568,7 @@
|
|||
});
|
||||
|
||||
// RECORDING
|
||||
$("[hoveraction='recording']", $parent).hoverIntent({
|
||||
$("[" + hoveractionAttr + "='recording']", $parent).hoverIntent({
|
||||
over: function(e) {
|
||||
var bubble = new JK.RecordingHoverBubble($(this).attr('recording-id'), e.pageX, e.pageY);
|
||||
showBubble(bubble, $(this));
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
.quick-options {
|
||||
margin: 0 0 35px 0;
|
||||
a {
|
||||
width:130px;
|
||||
width:135px;
|
||||
margin-left:0px;
|
||||
position:absolute;
|
||||
top:5px;
|
||||
|
|
@ -385,7 +385,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.session-musician-access-header, .session-fans-access-header {
|
||||
.session-musician-access-header, .session-fans-access-header, .session-friends-can-join-header {
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,12 +3,92 @@
|
|||
#findSession {
|
||||
|
||||
|
||||
.FindSessionScreen {
|
||||
height:100%;
|
||||
}
|
||||
|
||||
[data-react-class="FindSessionScreen"] {
|
||||
height:100%;
|
||||
}
|
||||
|
||||
.session-keyword-srch {
|
||||
|
||||
}
|
||||
|
||||
.musicians-category {
|
||||
|
||||
}
|
||||
|
||||
.musicians-detail > td {
|
||||
padding-bottom:20px;
|
||||
}
|
||||
.musicians-header {
|
||||
span {
|
||||
display:block;
|
||||
height:100%;
|
||||
margin:10px;
|
||||
|
||||
}
|
||||
}
|
||||
.find-session-help {
|
||||
background-color: #262626;
|
||||
max-width: 66%;
|
||||
border: 2px solid #333;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
/* margin-top: 20px; */
|
||||
margin: 30px auto;
|
||||
padding: 10px;
|
||||
width: 400px;
|
||||
|
||||
a {
|
||||
}
|
||||
li {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
h3 {
|
||||
text-align:center;
|
||||
font-weight:bold;
|
||||
margin: 0 0 10px 0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height:125%;
|
||||
margin: 0 0 10px 0;
|
||||
font-size:14px;
|
||||
|
||||
}
|
||||
p + h3 {
|
||||
margin-top:20px;
|
||||
}
|
||||
}
|
||||
|
||||
.none-found {
|
||||
text-align:center;
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
padding-left: 25px;
|
||||
padding-left: 35px;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: upright;
|
||||
position: absolute;
|
||||
height: calc(100% - 10px); // 10px comes from spacer height
|
||||
width: 20px;
|
||||
left: -21px;
|
||||
background-color: #ed3618;
|
||||
top: 0;
|
||||
border: 0px solid black;
|
||||
font-size: 11px;
|
||||
text-align: center;
|
||||
padding: 0 5px;
|
||||
margin: 0;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.header-zone {
|
||||
|
|
@ -65,7 +145,16 @@
|
|||
padding-bottom:20px;
|
||||
}
|
||||
|
||||
.sessions-for-me {
|
||||
.actions {
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
.end-of-results {
|
||||
position:relative;
|
||||
padding-bottom:20px;
|
||||
text-align:center;
|
||||
}
|
||||
.sessions-for-me, .sessions-for-open {
|
||||
clear:both;
|
||||
display:none;
|
||||
&.active {
|
||||
|
|
@ -73,6 +162,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.rsvp-icon {
|
||||
display: inline-block;
|
||||
background: url('/assets/content/rsvp-icon.jpg') no-repeat;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
.join-icon {
|
||||
display: inline-block;
|
||||
background: url('/assets/content/join-icon.jpg') no-repeat;
|
||||
|
|
@ -123,8 +218,8 @@
|
|||
.content-body-scroller {
|
||||
height:inherit;
|
||||
position:relative;
|
||||
display:block;
|
||||
overflow:auto
|
||||
height:calc(100% - 123px) ! important;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
.session-filter {
|
||||
|
|
@ -173,6 +268,10 @@
|
|||
margin-top:0;
|
||||
}
|
||||
|
||||
.none-yet {
|
||||
margin-left:36px;
|
||||
}
|
||||
|
||||
.latency-value {
|
||||
@include border-radius(2px);
|
||||
}
|
||||
|
|
@ -190,6 +289,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
a.start, a.cancel {
|
||||
color:#fc0;
|
||||
}
|
||||
|
||||
.listen-detail-hover {
|
||||
margin-left:5px;
|
||||
margin-top:0 !important;
|
||||
|
|
@ -203,17 +306,11 @@
|
|||
}
|
||||
.join-link-text {
|
||||
font-weight:bold;
|
||||
#position:relative;
|
||||
#left:6px;
|
||||
}
|
||||
|
||||
.rsvp-link {
|
||||
#position:relative;
|
||||
#left:0px;
|
||||
}
|
||||
.rsvp-link-text {
|
||||
font-weight:bold;
|
||||
#position:relative;
|
||||
#left:6px;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#session-settings {
|
||||
|
||||
width:500px;
|
||||
width:550px;
|
||||
|
||||
.dropdown-wrapper {
|
||||
width:100%;
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
}
|
||||
|
||||
.input-holder {
|
||||
width:350px;
|
||||
width:400px;
|
||||
}
|
||||
|
||||
.notation-entry {
|
||||
|
|
|
|||
|
|
@ -93,6 +93,11 @@ class ApiMusicSessionsController < ApiController
|
|||
end
|
||||
end
|
||||
|
||||
def sms_index_2
|
||||
@music_sessions = MusicSession.scheduled_index(current_user, params)
|
||||
@user_scores = {}
|
||||
end
|
||||
|
||||
def scheduled
|
||||
@music_sessions = MusicSession.scheduled(current_user)
|
||||
end
|
||||
|
|
@ -192,7 +197,8 @@ class ApiMusicSessionsController < ApiController
|
|||
params[:approval_required],
|
||||
params[:fan_chat],
|
||||
params[:fan_access],
|
||||
params[:session_controller])
|
||||
params[:session_controller],
|
||||
params[:friends_can_join])
|
||||
|
||||
if @music_session.errors.any?
|
||||
# we have to do this because api_session_detail_url will fail with a bad @music_session
|
||||
|
|
@ -234,6 +240,7 @@ class ApiMusicSessionsController < ApiController
|
|||
@music_session.approval_required = params[:approval_required] if params.include? :approval_required
|
||||
@music_session.fan_chat = params[:fan_chat] if params.include? :fan_chat
|
||||
@music_session.fan_access = params[:fan_access] if params.include? :fan_access
|
||||
@music_session.friends_can_join = params[:friends_can_join] if params.include? :friends_can_join
|
||||
@music_session.genre = Genre.find_by_id(params[:genres][0]) if params.include?(:genres) && params[:genres] && params[:genres].length > 0
|
||||
@music_session.legal_policy = params[:legal_policy] if params.include? :legal_policy
|
||||
@music_session.language = params[:language] if params.include? :language
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ if !current_user
|
|||
}
|
||||
else
|
||||
|
||||
attributes :id, :name, :description, :musician_access, :approval_required, :fan_access, :fan_chat, :band_id, :user_id, :claimed_recording_initiator_id, :track_changes_counter, :max_score, :backing_track_path, :metronome_active, :jam_track_initiator_id, :jam_track_id
|
||||
attributes :id, :name, :description, :musician_access, :approval_required, :friends_can_join, :fan_access, :fan_chat, :band_id, :user_id, :claimed_recording_initiator_id, :track_changes_counter, :max_score, :backing_track_path, :metronome_active, :jam_track_initiator_id, :jam_track_id
|
||||
|
||||
node :can_join do |session|
|
||||
session.can_join?(current_user, true)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ else
|
|||
attributes :id, :music_session_id, :name, :description, :musician_access, :approval_required, :fan_access, :fan_chat, :create_type,
|
||||
:band_id, :user_id, :genre_id, :created_at, :like_count, :comment_count, :play_count, :scheduled_duration,
|
||||
:language, :recurring_mode, :language_description, :scheduled_start_date, :access_description, :timezone, :timezone_id, :timezone_description,
|
||||
:musician_access_description, :fan_access_description, :session_removed_at, :legal_policy, :open_rsvps, :is_unstructured_rsvp?
|
||||
:musician_access_description, :fan_access_description, :session_removed_at, :legal_policy, :open_rsvps, :is_unstructured_rsvp?, :friends_can_join
|
||||
|
||||
node :can_join do |session|
|
||||
session.can_join?(current_user, true)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
child @music_sessions => :sessions do
|
||||
extends "api_music_sessions/show_history"
|
||||
end
|
||||
|
|
@ -1,60 +1,3 @@
|
|||
<!-- Find Session Screen -->
|
||||
<div layout="screen" layout-id="findSession" id="findSession" class="screen secondary">
|
||||
<div class="content">
|
||||
<div class="content-head">
|
||||
<div class="content-icon">
|
||||
<%= image_tag "content/icon_search.png", :size => "19x19" %>
|
||||
</div>
|
||||
|
||||
<h1>find a session</h1>
|
||||
|
||||
<%= render "screen_navigation" %>
|
||||
</div>
|
||||
<div class="content-body">
|
||||
<div class="content-body-scroller">
|
||||
<form id="find-session-form">
|
||||
<div class="session-filter">
|
||||
<div style="min-width:770px;">
|
||||
<div class="left ml35" style="padding-top:3px;">Filter Session List:</div>
|
||||
|
||||
|
||||
<!-- keyword filter -->
|
||||
<div class="search-box">
|
||||
<input id="session-keyword-srch" type="text" name="search" placeholder="Search by Keyword" />
|
||||
</div>
|
||||
|
||||
<div class="right mr10">
|
||||
<a id="btn-refresh" href="/client#/findSession" style="text-decoration:none;" class="button-grey">REFRESH<span class="extra"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="content-wrapper">
|
||||
<div id="sessions-active" class="session-container">
|
||||
<%= render :partial => "sessionList", :locals => {:title => "current, active sessions", :category => "sessions-active"} %>
|
||||
<br />
|
||||
<div class="paginate-wait">Fetching results...<div class="spinner-small"></div></div>
|
||||
<div id="no-active-sessions" class="end-of-list">
|
||||
End of list.
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div id="sessions-scheduled" class="session-container">
|
||||
<%= render :partial => "sessionList", :locals => {:title => "future, scheduled sessions", :category => "sessions-scheduled"} %>
|
||||
<br />
|
||||
<div class="paginate-wait">Fetching results...<div class="spinner-small"></div></div>
|
||||
<div id="no-scheduled-sessions" class="end-of-list">
|
||||
End of list.
|
||||
</div>
|
||||
<span class="btn-next-wrapper"><a href="/api/sessions/inactive?page=1" class="btn-next">Next</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- active session template -->
|
||||
<script type="text/template" id="template-active-session-row">
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
<div class="quick-options">
|
||||
<div class="quick-option"><a class="button-orange quick-start-solo" href="#" >QUICK START SOLO</a><p>Use this button to quick start a private session just for yourself. Good for solo practice and gear testing.</p></div>
|
||||
<div class="quick-option"><a class="button-orange quick-start-open" href="#" >QUICK START OPEN</a><p>Use this button to quick start an open session that anyone can join to play with you, and that fans can listen to.</p></div>
|
||||
<div class="quick-option"><a class="button-orange quick-start-friends" href="#" >QUICK START FRIENDS</a><p>Use this button to quick start a friends-only session. No invitations necessary for any of your friends. Good for those with select friends they always play with.</p></div>
|
||||
<div class="quick-option"><a class="button-orange start-or-schedule" href="#" >START OR SCHEDULE</a><p>Use this button start a wizard that will let you have more control over your session. Schedule future sessions. Start private sessions. Invite other musicians. And lots more...</p><a class="schedule-learn-more" href="https://forum.jamkazam.com/showthread.php?tid=4" rel="external">learn more</a></div>
|
||||
</div>
|
||||
<h2>featured sessions</h2>
|
||||
|
|
@ -390,6 +391,20 @@
|
|||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<h3 class="session-friends-can-join-header">How will you handle friend access?</h3>
|
||||
<select id="session-friends-can-join">
|
||||
<option value="true" selected="selected">Friends Can Always Join</option>
|
||||
<option value="false">Friends Follow Musician Access Rules</option>
|
||||
</select>
|
||||
<div id="session-friends-can-join-info" class="mt5">
|
||||
<div class="info-box" friends-can-join-type="true">
|
||||
Friends can join your session without any invitation.
|
||||
</div>
|
||||
<div class="info-box hidden" friends-can-join-type="false">
|
||||
Friends have to follow 'Musician Access' rules.
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<h3 class="session-fans-access-header">How will you handle fan access?</h3>
|
||||
<select id="session-fans-access">
|
||||
<!--<option value="listen-chat-band">Fans may listen, chat with the band</option>-->
|
||||
|
|
|
|||
|
|
@ -47,7 +47,14 @@
|
|||
%option{:value => "only-rsvp"} Only RSVP musicians may join
|
||||
%option{:value => "musicians"} Musicians may join at will
|
||||
%option{:value => "musicians-approval"} Musicians may join by approval
|
||||
|
||||
|
||||
.clearall.left.w20.ib.mb10
|
||||
Friends Can Join:
|
||||
.right.w75.ib.mb10
|
||||
%select{:name => "friends-can-join", :id => "session-settings-friends-can-join"}
|
||||
%option{:value => "true"} Friends Can Always Join
|
||||
%option{:value => "false"} Friends Follow Musician Access Rules
|
||||
|
||||
.clearall.left.w25.ib.mb10
|
||||
Fan Access:
|
||||
.right.w75.ib.mb10
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
<%= render "sidebar" %>
|
||||
<%= render "scheduledSession" %>
|
||||
<%= render "findSession" %>
|
||||
<%= render "findSession2" %>
|
||||
<%= render "session2" %>
|
||||
<%= render "profile" %>
|
||||
<%= render "bandProfile" %>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ SampleApp::Application.configure do
|
|||
|
||||
# Show full error reports and disable caching
|
||||
config.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
config.action_controller.perform_caching = true
|
||||
|
||||
# Don't care if the mailer can't send
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
|
|
@ -41,7 +41,7 @@ SampleApp::Application.configure do
|
|||
config.assets.compress = false
|
||||
|
||||
# Expands the lines which load the assets
|
||||
config.assets.debug = true
|
||||
config.assets.debug = false
|
||||
|
||||
# Set the logging destination(s)
|
||||
config.log_to = %w[stdout file]
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ Rails.application.routes.draw do
|
|||
# music sessions
|
||||
match '/sessions/:id/participants/legacy' => 'api_music_sessions#participant_create_legacy', :via => :post # can be removed when new Create Session comes in
|
||||
match '/sessions/:id/participants' => 'api_music_sessions#participant_create', :via => :post
|
||||
match '/participants/:id' => 'api_music_sessions#participant_show', :via => :tt, :as => 'api_session_participant_detail'
|
||||
match '/participants/:id' => 'api_music_sessions#participant_show', :via => :get, :as => 'api_session_participant_detail'
|
||||
match '/participants/:id' => 'api_music_sessions#participant_delete', :via => :delete
|
||||
match '/sessions/scheduled' => 'api_music_sessions#scheduled', :via => :get
|
||||
match '/sessions/scheduled_rsvp' => 'api_music_sessions#scheduled_rsvp', :via => :get
|
||||
|
|
@ -249,7 +249,7 @@ Rails.application.routes.draw do
|
|||
match '/sessions/friends' => 'api_music_sessions#friend_active_index', :via => :get
|
||||
match '/sessions/public' => 'api_music_sessions#public_index', :via => :get
|
||||
match '/sessions/active' => 'api_music_sessions#ams_index', :via => :get
|
||||
match '/sessions/inactive' => 'api_music_sessions#sms_index', :via => :get
|
||||
match '/sessions/inactive' => 'api_music_sessions#sms_index_2', :via => :get
|
||||
match '/sessions/:id' => 'api_music_sessions#show', :via => :get, :as => 'api_session_detail'
|
||||
match '/sessions/:id' => 'api_music_sessions#update', :via => :put
|
||||
match '/sessions/:id' => 'api_music_sessions#session_update', :via => :post
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class MusicSessionManager < BaseManager
|
|||
end
|
||||
|
||||
# Update the session. If a field is left out (meaning, it's set to nil), it's not updated.
|
||||
def update(current_user, music_session, name, description, genre, language, musician_access, approval_required, fan_chat, fan_access, session_controller_id)
|
||||
def update(current_user, music_session, name, description, genre, language, musician_access, approval_required, fan_chat, fan_access, session_controller_id, friends_can_join)
|
||||
|
||||
music_session.name = name unless name.nil?
|
||||
music_session.description = description unless description.nil?
|
||||
|
|
@ -80,6 +80,7 @@ class MusicSessionManager < BaseManager
|
|||
music_session.approval_required = approval_required unless approval_required.nil?
|
||||
music_session.fan_chat = fan_chat unless fan_chat.nil?
|
||||
music_session.fan_access = fan_access unless fan_access.nil?
|
||||
music_session.friends_can_join = friends_can_join unless friends_can_join.nil?
|
||||
session_controller = User.find(session_controller_id) if session_controller_id.present?
|
||||
should_tick = music_session.set_session_controller(current_user, session_controller)
|
||||
music_session.save
|
||||
|
|
|
|||
Loading…
Reference in New Issue