From 10543665ee02b10db0c9464409e672b5d4a39915 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Wed, 29 Apr 2020 15:51:50 -0500 Subject: [PATCH] wip --- admin/scratch.js.jsx.coffee | 0 db/manifest | 3 +- db/up/find_sessions_2020.sql | 3 + .../jam_ruby/models/active_music_session.rb | 93 ++++++ ruby/lib/jam_ruby/models/invited_user.rb | 2 +- ruby/lib/jam_ruby/models/music_session.rb | 3 + ruby/lib/jam_ruby/models/rsvp_request.rb | 7 + ruby/lib/jam_ruby/models/user.rb | 6 +- .../models/active_music_session_spec.rb | 169 +++++++++- web/app/assets/javascripts/jam_rest.js | 16 + .../FindSessionFriends.js.jsx.coffee | 133 ++++++++ .../FindSessionRow.js.jsx.coffee | 272 +++++++++++++++++ .../FindSessionScreen.js.jsx.coffee | 108 +++++++ .../stylesheets/client/findSession.scss | 44 +++ .../api_music_sessions_controller.rb | 8 + .../friend_active_index.rabl | 3 + .../api_music_sessions/public_index.rabl | 3 + web/app/views/clients/_findSession.html.erb | 288 +----------------- web/app/views/clients/_findSession2.html.erb | 287 +++++++++++++++++ .../views/users/_download_templates.html.slim | 6 +- web/config/routes.rb | 2 + 21 files changed, 1162 insertions(+), 294 deletions(-) create mode 100644 admin/scratch.js.jsx.coffee create mode 100644 db/up/find_sessions_2020.sql create mode 100644 web/app/assets/javascripts/react-components/FindSessionFriends.js.jsx.coffee create mode 100644 web/app/assets/javascripts/react-components/FindSessionRow.js.jsx.coffee create mode 100644 web/app/assets/javascripts/react-components/FindSessionScreen.js.jsx.coffee create mode 100644 web/app/views/api_music_sessions/friend_active_index.rabl create mode 100644 web/app/views/api_music_sessions/public_index.rabl create mode 100644 web/app/views/clients/_findSession2.html.erb diff --git a/admin/scratch.js.jsx.coffee b/admin/scratch.js.jsx.coffee new file mode 100644 index 000000000..e69de29bb diff --git a/db/manifest b/db/manifest index 266c37788..30258a277 100755 --- a/db/manifest +++ b/db/manifest @@ -391,4 +391,5 @@ limit_counter_reminders.sql amazon_v2.sql store_backend_details_rate_session.sql invited_user_receiver.sql -live_streams.sql \ No newline at end of file +live_streams.sql +find_sessions_2020.sql \ No newline at end of file diff --git a/db/up/find_sessions_2020.sql b/db/up/find_sessions_2020.sql new file mode 100644 index 000000000..92f2ccae3 --- /dev/null +++ b/db/up/find_sessions_2020.sql @@ -0,0 +1,3 @@ +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; +CREATE INDEX rsvp_request_music_session_id ON rsvp_requests USING btree (music_session_id); \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/active_music_session.rb b/ruby/lib/jam_ruby/models/active_music_session.rb index f93d0bf70..7d6e62228 100644 --- a/ruby/lib/jam_ruby/models/active_music_session.rb +++ b/ruby/lib/jam_ruby/models/active_music_session.rb @@ -243,6 +243,99 @@ module JamRuby return query end + + # all sessions that are private and active, yet I can see + def self.friend_active_index(user, options) + + session_id = options[:session_id] + genre = options[:genre] + lang = options[:lang] + keyword = options[:keyword] + offset = options[:offset] + limit = options[:limit] + + query = MusicSession.select('music_sessions.*') + + query = query.joins("INNER JOIN active_music_sessions ON music_sessions.id = active_music_sessions.id") + + # 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 + active_music_sessions.id = invitations.music_session_id AND invitations.receiver_id = '#{user.id}' + LEFT OUTER JOIN + friendships + ON + active_music_sessions.user_id = friendships.user_id AND friendships.friend_id = '#{user.id}' + LEFT OUTER JOIN + friendships as friendships_2 + ON + active_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("rsvp_requests.id IS NOT NULL OR invitations.id IS NOT NULL or active_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") + query + end + + # all sessions that are private and active, yet I can see + def self.public_index(user, options) + + session_id = options[:session_id] + genre = options[:genre] + lang = options[:lang] + keyword = options[:keyword] + offset = options[:offset] + limit = options[:limit] + + query = MusicSession.select('music_sessions.*') + + query = query.joins("INNER JOIN active_music_sessions ON music_sessions.id = active_music_sessions.id") + + query = query.where("musician_access = TRUE") + + + # 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") + query + end + + # This is a little confusing. You can specify *BOTH* friends_only and my_bands_only to be true # If so, then it's an OR condition. If both are false, you can get sessions with anyone. # note, this is mostly the same as above but includes paging through the result and and scores. diff --git a/ruby/lib/jam_ruby/models/invited_user.rb b/ruby/lib/jam_ruby/models/invited_user.rb index f66f3db9f..16be90d84 100644 --- a/ruby/lib/jam_ruby/models/invited_user.rb +++ b/ruby/lib/jam_ruby/models/invited_user.rb @@ -1,5 +1,5 @@ module JamRuby - class InvitedUser < ActiveRecord::Base + class InvitedUser < ActiveRecord::Base include HtmlSanitize html_sanitize strict: [:note] diff --git a/ruby/lib/jam_ruby/models/music_session.rb b/ruby/lib/jam_ruby/models/music_session.rb index 119568d18..811936873 100644 --- a/ruby/lib/jam_ruby/models/music_session.rb +++ b/ruby/lib/jam_ruby/models/music_session.rb @@ -52,6 +52,7 @@ module JamRuby has_many :fan_invitations, :foreign_key => "music_session_id", :inverse_of => :music_session, :class_name => "JamRuby::FanInvitation" has_many :invited_fans, :through => :fan_invitations, :class_name => "JamRuby::User", :foreign_key => "receiver_id", :source => :receiver has_many :rsvp_slots, :class_name => "JamRuby::RsvpSlot", :foreign_key => "music_session_id", :dependent => :destroy + has_many :rsvp_requests, :class_name => "JamRuby::RsvpRequest", :foreign_key => "music_session_id", :dependent => :destroy has_many :music_notations, :class_name => "JamRuby::MusicNotation", :foreign_key => "music_session_id" has_many :jam_track_session, :class_name => "JamRuby::JamTrackSession" has_many :broadcasts, :class_name => "JamRuby::Broadcast" @@ -359,6 +360,7 @@ module JamRuby rsvp = RsvpRequest.find_by_id(rsvp_request_slot.rsvp_request_id) new_rsvp = RsvpRequest.new new_rsvp.user_id = rsvp.user_id + new_rsvp.music_session_id = rsvp.music_session_id new_rsvp_req_slot = RsvpRequestRsvpSlot.new new_rsvp_req_slot.rsvp_request = new_rsvp @@ -379,6 +381,7 @@ module JamRuby if rsvp.canceled && !rsvp.cancel_all new_rsvp = RsvpRequest.new new_rsvp.user_id = rsvp.user_id + new_rsvp.music_session_id = rsvp.music_session_id new_rsvp_req_slot = RsvpRequestRsvpSlot.new new_rsvp_req_slot.rsvp_request = new_rsvp diff --git a/ruby/lib/jam_ruby/models/rsvp_request.rb b/ruby/lib/jam_ruby/models/rsvp_request.rb index 20c3b9e9a..ca4513c0b 100644 --- a/ruby/lib/jam_ruby/models/rsvp_request.rb +++ b/ruby/lib/jam_ruby/models/rsvp_request.rb @@ -2,6 +2,7 @@ module JamRuby class RsvpRequest < ActiveRecord::Base belongs_to :user, :class_name => "JamRuby::User" + belongs_to :music_session, :class_name => "JamRuby::MusicSession" has_many :rsvp_requests_rsvp_slots, :class_name => "JamRuby::RsvpRequestRsvpSlot", :foreign_key => "rsvp_request_id" has_many :rsvp_slots, :class_name => "JamRuby::RsvpSlot", :through => :rsvp_requests_rsvp_slots @@ -69,6 +70,8 @@ module JamRuby RsvpRequest.transaction do @rsvp = RsvpRequest.new @rsvp.user = user + @rsvp.music_session = music_session + @rsvp.chosen = true if params[:autoapprove] == true slot_ids = params[:rsvp_slots] @@ -165,6 +168,8 @@ module JamRuby end RsvpRequest.transaction do + + rsvp_request.chosen = true rsvp_responses = params[:rsvp_responses] if !rsvp_responses.blank? instruments = [] @@ -234,6 +239,8 @@ module JamRuby else raise StateError, "Invalid request." end + + rsvp_request.save end end diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 1d35b23fc..a3942e9dc 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -657,7 +657,8 @@ module JamRuby end def recording_count - self.recordings.size + #self.recordings.size + 0 end def age @@ -666,7 +667,8 @@ module JamRuby end def session_count - MusicSession.where("user_id = ? AND started_at IS NOT NULL", self.id).size + 0 + #MusicSession.where("user_id = ? AND started_at IS NOT NULL", self.id).size end # count up any session you are RSVP'ed to diff --git a/ruby/spec/jam_ruby/models/active_music_session_spec.rb b/ruby/spec/jam_ruby/models/active_music_session_spec.rb index d85623f52..8b8463f39 100644 --- a/ruby/spec/jam_ruby/models/active_music_session_spec.rb +++ b/ruby/spec/jam_ruby/models/active_music_session_spec.rb @@ -389,7 +389,174 @@ describe ActiveMusicSession do end end - describe "ams_index", no_transaction: true do + + describe "public index", no_transaction: false do + it "public_index" do + + creator = FactoryGirl.create(:user) + creator2 = FactoryGirl.create(:user) + earlier_session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Earlier Session") + later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session") + user = FactoryGirl.create(:user) + earlier_session.music_session.musician_access = true + earlier_session.music_session.save! + + + music_sessions = ActiveMusicSession.public_index(creator, {}).take(100) + music_sessions.should_not be_nil + music_sessions.length.should == 2 + end + end + + + describe "friend_active_index", no_transaction: false do + it "does not crash" do + + creator = FactoryGirl.create(:user) + creator2 = FactoryGirl.create(:user) + earlier_session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Earlier Session") + later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session") + user = FactoryGirl.create(:user) + earlier_session.music_session.musician_access = false + earlier_session.music_session.save! + + Friendship.save_using_models(creator, creator2) + + music_sessions = ActiveMusicSession.friend_active_index(creator, {}).take(100) + music_sessions.should_not be_nil + music_sessions.length.should == 2 + end + + describe "parameters" do + let(:creator_1) { FactoryGirl.create(:user, last_jam_locidispid: 4, last_jam_audio_latency: 8) } + let(:creator_conn_1) { FactoryGirl.create(:connection, user: creator_1, ip_address: '4.4.4.4', locidispid: 4, addr:4) } + let(:creator_2) { FactoryGirl.create(:user, last_jam_locidispid: 1, last_jam_audio_latency: 10) } + let(:creator_conn_2) { FactoryGirl.create(:connection, user: creator_2, ip_address: '4.4.4.4', locidispid: 1, addr:1) } + let(:creator_3) { FactoryGirl.create(:user, last_jam_locidispid: 2, last_jam_audio_latency: 12) } + let(:creator_conn_3) { FactoryGirl.create(:connection, user: creator_3, ip_address: '5.5.5.5', locidispid: 2, addr:2) } + let(:searcher_1) { FactoryGirl.create(:user, last_jam_locidispid: 5, last_jam_audio_latency: 6) } + let(:searcher_conn_1) { FactoryGirl.create(:connection, user: searcher_1, ip_address: '8.8.8.8', locidispid: 5, addr:5) } + let(:searcher_2) { FactoryGirl.create(:user, last_jam_locidispid: 3, last_jam_audio_latency: 14) } + let(:searcher_conn_2) { FactoryGirl.create(:connection, user: searcher_2, ip_address: '9.9.9.9', locidispid: 3, addr:3) } + + + let!(:music_session_1) { FactoryGirl.create(:active_music_session, :creator => creator_1, genre: Genre.find('african'), language: 'eng', description: "Bunny Jumps" ) } + let!(:music_session_2) { FactoryGirl.create(:active_music_session, :creator => creator_2, genre: Genre.find('ambient'), language: 'spa', description: "Play with us as we jam to beatles and bunnies") } + + let(:tracks) { [{'sound' => 'mono', 'client_track_id' => 'abc', 'instrument_id' => 'piano'}] } + + it "as invited" do + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, {}) + music_sessions.length.should == 0 + + Friendship.save_using_models(searcher_1, creator_1) + FactoryGirl.create(:invitation, music_session: music_session_1.music_session, sender: creator_1, receiver: searcher_1) + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, {}) + music_sessions.length.should == 1 + music_sessions[0].should == music_session_1.music_session + end + + it "as rsvp" do + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, {}) + music_sessions.length.should == 0 + + rsvp_slot = FactoryGirl.create(:rsvp_slot, music_session: music_session_1.music_session, instrument: Instrument.find('piano')) + rsvp_request = FactoryGirl.create(:rsvp_request, user: searcher_1, chosen:true, music_session: music_session_1.music_session) + rsvp_request_rsvp_slot = FactoryGirl.create(:rsvp_request_rsvp_slot, chosen:true, rsvp_request: rsvp_request, rsvp_slot:rsvp_slot) + + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, {}) + music_sessions.length.should == 1 + music_sessions[0].should == music_session_1.music_session + end + + describe "as friends" do + + before(:each) { + Friendship.save_using_models(searcher_1, creator_1) + Friendship.save_using_models(searcher_1, creator_2) + } + + it "offset/limit" do + # put creators in the session + creator_conn_1.join_the_session(music_session_1.music_session, true, tracks, creator_1, 10) + creator_conn_1.errors.any?.should be_false + creator_conn_2.join_the_session(music_session_2.music_session, true, tracks, creator_2, 10) + creator_conn_2.errors.any?.should be_false + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, {}) + music_sessions.length.should == 2 + music_sessions[0].should == music_session_1.music_session + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, offset:0, limit:1) + music_sessions.length.should == 1 + music_sessions[0].should == music_session_1.music_session + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, offset:1, limit:2) + music_sessions.length.should == 1 + music_sessions[0].should == music_session_2.music_session + end + + it "genre" do + # verify we can get all 2 sessions + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, {}) + music_sessions.length.should == 2 + + # get only african + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, genre: 'african') + music_sessions.length.should == 1 + music_sessions[0].genre.should == Genre.find('african') + + # get only ambient + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, genre: 'ambient') + music_sessions.length.should == 1 + music_sessions[0].genre.should == Genre.find('ambient') + end + + it "language" do + # verify we can get all 2 sessions + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, {}) + music_sessions.length.should == 2 + + # get only english + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, lang: 'eng') + music_sessions.length.should == 1 + music_sessions[0].language.should == 'eng' + + # get only ambient + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, lang: 'spa') + music_sessions.length.should == 1 + music_sessions[0].language.should == 'spa' + + end + + it "keyword" do + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, keyword: 'Jump') + music_sessions.length.should == 1 + + music_sessions[0].should == music_session_1.music_session + music_sessions = ams(searcher_1, keyword: 'Bunny') + music_sessions.length.should == 2 + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, keyword: 'play') + music_sessions.length.should == 1 + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, keyword: 'bun') + music_sessions.length.should == 2 + + + music_sessions = ActiveMusicSession.friend_active_index(searcher_1, keyword: 'bunny play') + music_sessions.length.should == 1 + end + end + end + + end + + describe "ams_index", no_transaction: true do it "does not crash" do creator = FactoryGirl.create(:user, last_jam_locidispid: 1, last_jam_audio_latency: 5) diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 36d3d98d4..5f5a823f9 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -145,6 +145,20 @@ }); } + function findFriendSessions(query) { + return $.ajax({ + type: "GET", + url: "/api/sessions/friends?" + $.param(query) + }); + } + + function findPublicSessions(query) { + return $.ajax({ + type: "GET", + url: "/api/sessions/public?" + $.param(query) + }); + } + function findActiveSessions(query) { return $.ajax({ type: "GET", @@ -3097,6 +3111,8 @@ this.listOnboardings = listOnboardings; this.getOnboarding = getOnboarding; this.updateOnboarding = updateOnboarding; + this.findFriendSessions = findFriendSessions; + this.findPublicSessions = findPublicSessions; return this; }; })(window, jQuery); diff --git a/web/app/assets/javascripts/react-components/FindSessionFriends.js.jsx.coffee b/web/app/assets/javascripts/react-components/FindSessionFriends.js.jsx.coffee new file mode 100644 index 000000000..22cd05a6a --- /dev/null +++ b/web/app/assets/javascripts/react-components/FindSessionFriends.js.jsx.coffee @@ -0,0 +1,133 @@ +context = window + +@FindSessionFriends = React.createClass({ + + mixins: [Reflux.listenTo(@AppStore, "onAppInit")] + + 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}) + + sessionResults: () -> + results = [] + for session in @state.sessions + results.push(``) + results + + render: () -> + results = @sessionResults() + + className = "sessions-for-me" + + if(@props.active) + className = className + " active" + + `
+
+
+
+

sessions for me

+
+ +
+ + + + + + + {results} +
SESSIONMUSICIANSACTIONS
+
+
+
+
+
` + + + defaultQuery: (extra) -> + query = + limit: @LIMIT + offset: @state.currentPage * @LIMIT + + $.extend(query, extra) + + componentDidMount: () -> + @EVENTS = context.JK.EVENTS + @rest = context.JK.Rest() + @logger = context.JK.logger + + @search() + + componentDidUpdate: () -> + $root = $(this.getDOMNode()) + $scroller = $root.find('.content-body-scroller') + + 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 + @registerInfiniteScroll($scroller) + + registerInfiniteScroll: ($scroller) -> + $scroller.off('scroll') + $scroller.on('scroll', () => + + # be sure to not fire off many refreshes when user hits the bottom + return if @refreshing + + if $scroller.scrollTop() + $scroller.innerHeight() + 100 >= $scroller[0].scrollHeight + $scroller.append('
... Loading more Sessions ...
') + @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}) + ) + ) + + onAppInit: (@app) -> + return +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/FindSessionRow.js.jsx.coffee b/web/app/assets/javascripts/react-components/FindSessionRow.js.jsx.coffee new file mode 100644 index 000000000..2cc6f3584 --- /dev/null +++ b/web/app/assets/javascripts/react-components/FindSessionRow.js.jsx.coffee @@ -0,0 +1,272 @@ +context = window +rest = window.JK.Rest() +logger = context.JK.logger + +@FindSessionRow = React.createClass({ + + createInstrument: (participant) -> + + instruments = [] + existingTracks = [] + for j in [0 .. participant.tracks.length] + + track = participant.tracks[j] + + if existingTracks.indexOf(track.instrument_id) < 0 + existingTracks.push(track.instrument_id) + logger.debug("Find:Finding instruments. Participant tracks:", participant.tracks) + inst = context.JK.getInstrumentIcon24(track.instrument_id) + instruments.push(``) + + instruments + + + 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 = '' + + ` + + + + + + + {musician_name} + + +
{instruments}
+ + {more_link}  + ` + + + createOpenSlot:(slot) -> + + + ` + + + + +
{instrument} ({proficiency})
+ + {more_link}  + ` + + createRsvpUser: (user, session, isLast) -> + instrumentLogoHtml = [] + + if user.instrument_list + for j in [0 .. user.instrument_list.length] + instrument = user.instrument_list[j]; + inst = context.JK.getInstrumentIcon24(instrument.id); + instrumentLogoHtml.push(``) + + moreLinkHtml = ''; + if isLast + moreLinkHtml = `more` + + instruments = @createInstrument(user) + 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 = '' + + ` + + + + + + + {musician_name} + + +
{instruments}
+ + {more_link}  + ` + + + + inSessionUsersHtml: (session) -> + inSessionUsers = [] + + result = [] + if session.active_music_session && "participants" in session.active_music_session && session.active_music_session.participants.length > 0 + for i in [0 .. session.active_music_session.participants.length] + participant = session.active_music_session.participants[i] + inSessionUsers.push(participant.user.id); + result.push(@createInSessionUser(participant)) + + return [result, inSessionUsers] + + + createRsvpUsers:( ) -> + + session = @props.session + + firstResults = [] + lastResults = [] + + approvedRsvpCount = session.approved_rsvps.length + + if session.approved_rsvps + first = session.approved_rsvps.slice(0, 3) + last = session.approved_rsvps.slice(3) + + for i in [0..first] + user = first[i] + firstResults.push(@createRsvpUser(user, session, approvedRsvpCount > 3 && i == 2)) + for i in [0..last] + user = last[i] + lastResults.push(@createRsvpUser(user, session, false)) + + [firstResults, lastResults] + + + + createOpenSlots: () -> + session = @prop.session + + firstResults = [] + remainingResults = [] + + if session['is_unstructured_rsvp?'] + firstResults.push(@createOpenSlot({description: 'Any Instrument'})) + + if session.open_slots + openSlotCount = session.open_slots.length + for i in [0 .. openSlotCount] + openSlot = session.open_slots[i] + if i < 3 + firstResults.push(@createOpenSlot(session.open_slots[i], openSlotCount > 3 && i == 2)) + else + remainingResults.push(@createOpenSlot(session.open_slots[i], false)) + + return [firstResults, remainingResults] + + showJoinLinks: (inSessionUsers) -> + session = @prop.session + showJoinLink = session.musician_access + if session.approved_rsvps + approvedRsvpCount = session.approved_rsvps.length + for i in [0 .. approvedRsvpCount] + # do not show the user in this section if he is already in the session + if $.inArray(session.approved_rsvps[i].id, inSessionUsers) == -1 + if session.approved_rsvps[i].id == context.JK.currentUserId + showJoinLink = true + else + showJoinLink = true + + showJoinLink + + + render: () -> + + session = @props.session + + id = session.id + name = session.name + description = session.description || "(No description)" + genres = '(' + session.genres.join (', ') + ')' + [in_session_musicians, inSessionUsers] = @inSessionUsersHtml() + [rsvp_musicians_first_3, rsvp_musicians_remaining] = @createRsvpUsers() + [open_slots_first_3, open_slots_remaining] = @createOpenSlots() + showJoinLink = @showJoinLink(inSessionUsers) + showListenLink = session.fan_access && session.active_music_session && session.active_music_session.mount + join_link_display_style = {display: "none"} + 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 = '' + + if !session.fan_access + listen_link_text = '' + else if session.active_music_session && session.active_music_session.mount + listen_link_text = 'Listen' + else + listen_link_text = ''; + + + ` + + + + + + + + + +
{name}{genres}
{description}
+ + + + + + + + + + + + + + + +
In Session: + + {in_session_musicians} +
+
RSVPs: + + {rsvp_musicians_first_3} +
+
+ + {rsvp_musicians_remaining} +
+
+
Still Needed: + + {open_slots_first_3} +
+
+ + {open_slots_remaining} +
+
+
+ + +
+ + + +
+ {listen_link_text}? +
+
+ + + + Join +
+ + + ` +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/FindSessionScreen.js.jsx.coffee b/web/app/assets/javascripts/react-components/FindSessionScreen.js.jsx.coffee new file mode 100644 index 000000000..ca23a89f5 --- /dev/null +++ b/web/app/assets/javascripts/react-components/FindSessionScreen.js.jsx.coffee @@ -0,0 +1,108 @@ +context = window +MIX_MODES = context.JK.MIX_MODES + + +@FindSessionScreen = React.createClass({ + + mixins: [Reflux.listenTo(@AppStore, "onAppInit"), Reflux.listenTo(@UserStore, "onUserChanged")] + + LIMIT: 20 + instrument_logo_map: context.JK.getInstrumentIconMap24() + + getInitialState: () -> + {activeTab: 'friends', search: '', type: 'user-input'} + + + generateProperties: (tab) -> + properties = {} + properties['active'] = @state.activeTab == tab + properties + + generateTabClasses: (tab) -> + classes = {} + classes['button-orange'] = true + classes['find-tab'] = true + classes[tab] = true + + if @state.activeTab == tab + classes['active'] = true + + classNames(classes) + + render: () -> + + friendTabClasses = @generateTabClasses('friends') + publicTabClasses = @generateTabClasses('public') + scheduledTabClasses = @generateTabClasses('scheduled') + + friendProperties = @generateProperties('friends') + publicProperties = @generateProperties('public') + scheduledProperties = @generateProperties('scheduled') + + search = '' + + `
+
+
+
+
+ +
+
+
+ + +
+
` + + + + componentDidMount: () -> + return + + componentDidUpdate: () -> + return + + beforeShow: () -> + return + + afterShow: () -> + return + + onAppInit: (@app) -> + @EVENTS = context.JK.EVENTS + @rest = context.JK.Rest() + @logger = context.JK.logger + + screenBindings = + 'beforeShow': @beforeShow + 'afterShow': @afterShow + + @app.bindScreen('findSession', screenBindings) + + onUserChanged: (userState) -> + @user = userState?.user +}) \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/findSession.scss b/web/app/assets/stylesheets/client/findSession.scss index 8161e570b..6843e688f 100644 --- a/web/app/assets/stylesheets/client/findSession.scss +++ b/web/app/assets/stylesheets/client/findSession.scss @@ -2,6 +2,49 @@ #findSession { + .btn-refresh { + position: absolute; + right: 2%; + top: 13px; + margin-right: 0; + } + + .session-keyword-srch { + + } + + .tabs { + padding-left: 25px; + } + .find-tab { + + float: left; + margin: 0 10px; + + &.active { + } + } + + .sessions-for-me { + display:none; + &.active { + display:block; + } + } + + .join-icon { + background: url('/assets/content/join-icon.jpg') no-repeat; + height: 37px; + width: 40px; + } + + .listen-icon { + background: url('/assets/content/listen-icon.jpg') no-repeat; + height: 40px; + width: 40px; + } + + .paginate-wait { margin:auto; text-align:center; @@ -45,6 +88,7 @@ min-height:20px; overflow-x:visible; vertical-align:middle; + position:relative; } .session-filter select { diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index 2df6c2a73..da6440c04 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -62,6 +62,14 @@ class ApiMusicSessionsController < ApiController limit: params[:limit]) end + def friend_active_index + @music_sessions = ActiveMusicSession.friend_active_index(current_user, params) + end + + def public_index + @music_sessions = ActiveMusicSession.public_index(current_user, params) + end + def ams_index # returns a relation which will produce a list of music_sessions which are active and augmented with attributes # tag and latency, then sorted by tag, latency, and finally music_sessions.id (for stability). the list is diff --git a/web/app/views/api_music_sessions/friend_active_index.rabl b/web/app/views/api_music_sessions/friend_active_index.rabl new file mode 100644 index 000000000..17684bcd0 --- /dev/null +++ b/web/app/views/api_music_sessions/friend_active_index.rabl @@ -0,0 +1,3 @@ +child @music_sessions => :sessions do + extends "api_music_sessions/show_history" +end diff --git a/web/app/views/api_music_sessions/public_index.rabl b/web/app/views/api_music_sessions/public_index.rabl new file mode 100644 index 000000000..17684bcd0 --- /dev/null +++ b/web/app/views/api_music_sessions/public_index.rabl @@ -0,0 +1,3 @@ +child @music_sessions => :sessions do + extends "api_music_sessions/show_history" +end diff --git a/web/app/views/clients/_findSession.html.erb b/web/app/views/clients/_findSession.html.erb index e78ec34b6..550afc5f9 100644 --- a/web/app/views/clients/_findSession.html.erb +++ b/web/app/views/clients/_findSession.html.erb @@ -10,294 +10,10 @@ <%= render "screen_navigation" %> +
-
-
-
-
-
Filter Session List:
- - -
- <%= render "genreSelector" %> -
- - - - - -
- -
- - - - -
- REFRESH -
-
-
-
-
-
- <%= render :partial => "sessionList", :locals => {:title => "current, active sessions", :category => "sessions-active"} %> -
-
Fetching results...
-
- End of list. -
-
-
-
- <%= render :partial => "sessionList", :locals => {:title => "future, scheduled sessions", :category => "sessions-scheduled"} %> -
-
Fetching results...
-
- End of list. -
- Next -
-
-
-
-
+ <%= react_component 'FindSessionScreen', {} %>
- - - - - - - - - - - - - diff --git a/web/app/views/clients/_findSession2.html.erb b/web/app/views/clients/_findSession2.html.erb new file mode 100644 index 000000000..eab6bb8b1 --- /dev/null +++ b/web/app/views/clients/_findSession2.html.erb @@ -0,0 +1,287 @@ + +
+
+
+
+ <%= image_tag "content/icon_search.png", :size => "19x19" %> +
+ +

find a session

+ + <%= render "screen_navigation" %> +
+
+
+
+
+
+
Filter Session List:
+ + + + + +
+ REFRESH +
+
+
+
+
+
+ <%= render :partial => "sessionList", :locals => {:title => "current, active sessions", :category => "sessions-active"} %> +
+
Fetching results...
+
+ End of list. +
+
+
+
+ <%= render :partial => "sessionList", :locals => {:title => "future, scheduled sessions", :category => "sessions-scheduled"} %> +
+
Fetching results...
+
+ End of list. +
+ Next +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + diff --git a/web/app/views/users/_download_templates.html.slim b/web/app/views/users/_download_templates.html.slim index 1b5aa7855..4a5842374 100644 --- a/web/app/views/users/_download_templates.html.slim +++ b/web/app/views/users/_download_templates.html.slim @@ -9,7 +9,7 @@ script type="text/template" id="client-download-blurb-contents" h5 SYSTEM REQUIREMENTS: | {% if(data.platform == "Win32") { %} ul.windows-requirements - li Windows 7 or 8, 64-bit (32-bit not supported) + li Windows 7, 8, or 10 - 64-bit (32-bit not supported) li Dual core processor or higher li 75MB hard disk space for app li External audio interface recommended (but you can start with built-in mic and & headphone jack) @@ -18,7 +18,7 @@ script type="text/template" id="client-download-blurb-contents" li Broadband Internet service with 1Mbps uplink bandwidth for real-time online sessions | {% } else if(data.platform == "MacOSX") { %} ul.mac-requirements - li Mac OS X 10.7 or higher, 64-bit + li Mac OS X 10.8 or higher, 64-bit li Dual-core processor or higher li 75MB hard disk space for app li External audio interface recommended (but you can start with built-in mic and & headphone jack) @@ -45,4 +45,4 @@ script type="text/template" id="client-download-select-others" br | Click here for to get JamKazam br - | for {{data.platformDisplay1}} \ No newline at end of file + | for {{data.platformDisplay1}} ' '' \ No newline at end of file diff --git a/web/config/routes.rb b/web/config/routes.rb index bdba4420c..ebb03534b 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -244,6 +244,8 @@ Rails.application.routes.draw do match '/sessions/scheduled' => 'api_music_sessions#scheduled', :via => :get match '/sessions/scheduled_rsvp' => 'api_music_sessions#scheduled_rsvp', :via => :get match '/sessions/legacy' => 'api_music_sessions#create_legacy', :via => :post + 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/:id' => 'api_music_sessions#show', :via => :get, :as => 'api_session_detail'