diff --git a/admin/Gemfile b/admin/Gemfile index 2e1799c5d..a2544488b 100644 --- a/admin/Gemfile +++ b/admin/Gemfile @@ -109,6 +109,7 @@ group :development, :test do gem 'database_cleaner', '0.7.0' gem 'launchy' gem 'faker', '1.3.0' + gem 'puma' end group :test do diff --git a/admin/app/admin/broadcast_notifications.rb b/admin/app/admin/broadcast_notifications.rb new file mode 100644 index 000000000..211d9298a --- /dev/null +++ b/admin/app/admin/broadcast_notifications.rb @@ -0,0 +1,26 @@ +ActiveAdmin.register JamRuby::BroadcastNotification, :as => 'BroadcastNotification' do + + menu :label => 'Notifications' + + config.sort_order = 'created_at_desc' + config.batch_actions = false + config.clear_action_items! + config.filters = false + + action_item :only => :index do + link_to "New Broadcast" , "broadcast_notifications/new" + end + + show do + attributes_table do + row :title + row :message + row :button_label + row :button_url + row :frequency + row :frequency_distribution + end + end + + +end diff --git a/admin/app/controllers/email_controller.rb b/admin/app/controllers/email_controller.rb new file mode 100644 index 000000000..bcfd0e7bb --- /dev/null +++ b/admin/app/controllers/email_controller.rb @@ -0,0 +1,20 @@ +require 'csv' + +class EmailController < ApplicationController + + respond_to :csv + + def dump_emailables + + if params[:code] != Rails.application.config.email_dump_code + render :text => "", :status => 404 + return + end + + headers['Content-Disposition'] = "attachment; filename=\"user-list.csv\"" + headers['Content-Type'] ||= 'text/csv' + + @users = User.where(subscribe_email: true) + end + +end \ No newline at end of file diff --git a/admin/app/views/email/dump_emailables.csv.erb b/admin/app/views/email/dump_emailables.csv.erb new file mode 100644 index 000000000..778d5dc89 --- /dev/null +++ b/admin/app/views/email/dump_emailables.csv.erb @@ -0,0 +1,2 @@ +<%- headers = ['email', 'name', 'unsubscribe_token'] -%> +<%= CSV.generate_line headers %><%- @users.each do |user| -%><%= CSV.generate_line([user.email, user.name, user.unsubscribe_token]) %><%- end -%> \ No newline at end of file diff --git a/admin/config/application.rb b/admin/config/application.rb index 9add98380..0e13be779 100644 --- a/admin/config/application.rb +++ b/admin/config/application.rb @@ -151,5 +151,7 @@ module JamAdmin config.jamtracks_dir = ENV['JAMTRACKS_DIR'] || File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "jamtracks")) config.jmep_dir = ENV['JMEP_DIR'] || File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "jmep")) + + config.email_dump_code = 'rcAUyC3TZCbgGx4YQpznBRbNnQMXW5iKTzf9NSBfzMLsnw9dRQ' end end diff --git a/admin/config/routes.rb b/admin/config/routes.rb index bae57c044..4a7424abd 100644 --- a/admin/config/routes.rb +++ b/admin/config/routes.rb @@ -34,6 +34,8 @@ JamAdmin::Application.routes.draw do match '/api/mix/:id/enqueue' => 'admin/mixes#mix_again', :via => :post match '/api/checks/latency_tester' => 'checks#check_latency_tester', :via => :get + match '/api/users/emailables/:code' => 'email#dump_emailables', :via => :get + mount Resque::Server.new, :at => "/resque" diff --git a/db/Gemfile.lock b/db/Gemfile.lock index eb6aee107..8d6d039c2 100644 --- a/db/Gemfile.lock +++ b/db/Gemfile.lock @@ -16,3 +16,6 @@ PLATFORMS DEPENDENCIES pg_migrate (= 0.1.13) + +BUNDLED WITH + 1.10.3 diff --git a/db/manifest b/db/manifest index 4ca6b3433..a3bddb189 100755 --- a/db/manifest +++ b/db/manifest @@ -292,4 +292,6 @@ signing.sql optimized_redeemption.sql optimized_redemption_warn_mode.sql affiliate_partners2.sql -enhance_band_profile.sql \ No newline at end of file +enhance_band_profile.sql +broadcast_notifications.sql +broadcast_notifications_fk.sql diff --git a/db/up/broadcast_notifications.sql b/db/up/broadcast_notifications.sql new file mode 100644 index 000000000..5a7cb80aa --- /dev/null +++ b/db/up/broadcast_notifications.sql @@ -0,0 +1,22 @@ +CREATE TABLE broadcast_notifications ( + id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), + title VARCHAR(64), + message VARCHAR(256), + button_label VARCHAR(32), + button_url VARCHAR, + frequency INTEGER DEFAULT 0, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE broadcast_notification_views ( + id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id varchar(64) NOT NULL REFERENCES users(id), + broadcast_notification_id varchar(64) NOT NULL REFERENCES broadcast_notifications(id) ON DELETE CASCADE, + view_count INTEGER DEFAULT 0, + active_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX user_broadcast_idx ON broadcast_notification_views(user_id, broadcast_notification_id); diff --git a/db/up/broadcast_notifications_fk.sql b/db/up/broadcast_notifications_fk.sql new file mode 100644 index 000000000..001c8c708 --- /dev/null +++ b/db/up/broadcast_notifications_fk.sql @@ -0,0 +1,2 @@ +ALTER TABLE broadcast_notification_views DROP CONSTRAINT broadcast_notification_views_user_id_fkey; +ALTER TABLE broadcast_notification_views ADD CONSTRAINT broadcast_notification_views_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; \ No newline at end of file diff --git a/db/up/enhance_band_profile.sql b/db/up/enhance_band_profile.sql index 2a526a3eb..ed8fc29dd 100644 --- a/db/up/enhance_band_profile.sql +++ b/db/up/enhance_band_profile.sql @@ -1,5 +1,5 @@ -ALTER TABLE bands ADD COLUMN band_type VARCHAR(16) DEFAULT 'not specified'; -ALTER TABLE bands ADD COLUMN band_status VARCHAR(16) DEFAULT 'not specified'; +ALTER TABLE bands ADD COLUMN band_type VARCHAR(16) DEFAULT ''; +ALTER TABLE bands ADD COLUMN band_status VARCHAR(16) DEFAULT ''; ALTER TABLE bands ADD COLUMN concert_count SMALLINT DEFAULT 0; ALTER TABLE bands ADD COLUMN add_new_members BOOLEAN DEFAULT FALSE; ALTER TABLE bands ADD COLUMN play_commitment SMALLINT DEFAULT 0; diff --git a/ruby/Gemfile b/ruby/Gemfile index f27e34015..d46e44e82 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -24,7 +24,7 @@ gem 'uuidtools', '2.1.2' gem 'bcrypt-ruby', '3.0.1' gem 'ruby-protocol-buffers', '1.2.2' gem 'eventmachine', '1.0.3' -gem 'amqp', '1.0.2' +gem 'amqp', '1.0.2' gem 'will_paginate' gem 'actionmailer', '3.2.13' gem 'sendgrid', '1.2.0' @@ -63,6 +63,7 @@ group :test do gem 'timecop' gem 'rspec-prof' gem 'time_difference' + gem 'byebug' end # Specify your gem's dependencies in jam_ruby.gemspec diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index d19e158b4..2878fe935 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -225,6 +225,8 @@ require "jam_ruby/models/text_message" require "jam_ruby/models/sale" require "jam_ruby/models/sale_line_item" require "jam_ruby/models/recurly_transaction_web_hook" +require "jam_ruby/models/broadcast_notification" +require "jam_ruby/models/broadcast_notification_view" require "jam_ruby/jam_tracks_manager" require "jam_ruby/jam_track_importer" require "jam_ruby/jmep_manager" diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 6a855c442..47b5cfe97 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -31,8 +31,8 @@ module JamRuby has_many :musician_instruments, :class_name => "JamRuby::MusicianInstrument", :foreign_key=> 'player_id' has_many :instruments, :through => :musician_instruments, :class_name => "JamRuby::Instrument", :foreign_key=> 'player_id' - has_many :online_presences, :class_name => "JamRuby::OnlinePresence" - has_many :performance_samples, :class_name => "JamRuby::PerformanceSample" + has_many :online_presences, :class_name => "JamRuby::OnlinePresence", :foreign_key=> 'player_id' + has_many :performance_samples, :class_name => "JamRuby::PerformanceSample", :foreign_key=> 'player_id' # musicians @@ -208,7 +208,6 @@ module JamRuby end online_presences = params[:online_presences] - Rails.logger.info("ONLINE_PRESENCE: #{online_presences.inspect} / #{params.inspect}") if online_presences.present? online_presences.each do |op| new_presence = OnlinePresence.create(band, op, false) diff --git a/ruby/lib/jam_ruby/models/broadcast_notification.rb b/ruby/lib/jam_ruby/models/broadcast_notification.rb new file mode 100644 index 000000000..24c19cc71 --- /dev/null +++ b/ruby/lib/jam_ruby/models/broadcast_notification.rb @@ -0,0 +1,51 @@ +module JamRuby + class BroadcastNotification < ActiveRecord::Base + + attr_accessible :title, :message, :button_label, :frequency, :button_url, as: :admin + + has_many :user_views, class_name: 'JamRuby::BroadcastNotificationView', dependent: :destroy + + validates :button_label, presence: true, length: {maximum: 14} + validates :message, presence: true, length: {maximum: 200} + validates :title, presence: true, length: {maximum: 50} + + def self.next_broadcast(user) + self.viewable_notifications(user).limit(1).first + end + + def self.viewable_notifications(user) + self.select('broadcast_notifications.*, bnv.updated_at AS bnv_updated_at') + .joins("LEFT OUTER JOIN broadcast_notification_views AS bnv ON bnv.broadcast_notification_id = broadcast_notifications.id AND (bnv.user_id IS NULL OR (bnv.user_id = '#{user.id}'))") + .where(['broadcast_notifications.frequency > 0']) + .where(['bnv.user_id IS NULL OR bnv.active_at < NOW()']) + .where(['bnv.user_id IS NULL OR broadcast_notifications.frequency > bnv.view_count']) + .order('bnv_updated_at NULLS FIRST') + end + + def did_view(user) + bnv = BroadcastNotificationView + .where(broadcast_notification_id: self.id, user_id: user.id) + .limit(1) + .first + + unless bnv + bnv = user_views.new() + bnv.user = user + bnv.active_at = Time.now - 10 + end + + bnv = user_views.new(user: user) unless bnv + bnv.view_count += 1 + bnv.save + bnv + end + + def frequency_distribution + @distribution ||= BroadcastNotificationView + .where(broadcast_notification_id: self.id) + .group(:view_count) + .count + end + + end +end diff --git a/ruby/lib/jam_ruby/models/broadcast_notification_view.rb b/ruby/lib/jam_ruby/models/broadcast_notification_view.rb new file mode 100644 index 000000000..926ddc12c --- /dev/null +++ b/ruby/lib/jam_ruby/models/broadcast_notification_view.rb @@ -0,0 +1,8 @@ +module JamRuby + class BroadcastNotificationView < ActiveRecord::Base + + belongs_to :broadcast_notification, :class_name => 'JamRuby::BroadcastNotification' + belongs_to :user, :class_name => 'JamRuby::User' + + end +end diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb index e2a45863d..90cd48c44 100644 --- a/ruby/spec/factories.rb +++ b/ruby/spec/factories.rb @@ -193,7 +193,7 @@ FactoryGirl.define do end factory :invitation, :class => JamRuby::Invitation do - + end factory :friendship, :class => JamRuby::Friendship do @@ -218,7 +218,7 @@ FactoryGirl.define do band.genres << Genre.first } end - + factory :genre, :class => JamRuby::Genre do description { |n| "Genre #{n}" } end @@ -239,7 +239,7 @@ FactoryGirl.define do end factory :video_source, :class => JamRuby::VideoSource do - #client_video_source_id "test_source_id" + #client_video_source_id "test_source_id" sequence(:client_video_source_id) { |n| "client_video_source_id#{n}"} end @@ -269,7 +269,7 @@ FactoryGirl.define do association :recording, factory: :recording end - factory :recorded_video, :class => JamRuby::RecordedVideo do + factory :recorded_video, :class => JamRuby::RecordedVideo do sequence(:client_video_source_id) { |n| "client_video_source_id-#{n}"} fully_uploaded true length 1 @@ -633,9 +633,9 @@ FactoryGirl.define do data Faker::Lorem.sentence end - factory :rsvp_slot, class: JamRuby::RsvpSlot do + factory :rsvp_slot, :class => JamRuby::RsvpSlot do - proficiency_level 'beginner' + proficiency_level "beginner" instrument { Instrument.find('electric guitar') } factory :chosen_rsvp_slot do @@ -643,10 +643,10 @@ FactoryGirl.define do user nil end - after(:create) { |rsvp_slot, evaluator| + after(:create) do |rsvp_slot, evaluator| rsvp_request = FactoryGirl.create(:rsvp_request, user: evaluator.user) rsvp_request_rsvp_slot = FactoryGirl.create(:rsvp_request_rsvp_slot, chosen:true, rsvp_request: rsvp_request, rsvp_slot:rsvp_slot) - } + end end end @@ -686,7 +686,7 @@ FactoryGirl.define do end end - factory :rsvp_request_rsvp_slot, class: JamRuby::RsvpRequestRsvpSlot do + factory :rsvp_request_rsvp_slot, :class => JamRuby::RsvpRequestRsvpSlot do chosen false end @@ -798,6 +798,13 @@ FactoryGirl.define do end end + factory :broadcast_notification, :class => JamRuby::BroadcastNotification do + title Faker::Lorem.sentence[0...50] + message Faker::Lorem.paragraph[0...200] + button_label Faker::Lorem.words(2).join(' ')[0...14] + frequency 3 + end + factory :affiliate_partner, class: 'JamRuby::AffiliatePartner' do sequence(:partner_name) { |n| "partner-#{n}" } entity_type 'Individual' @@ -824,6 +831,6 @@ FactoryGirl.define do factory :affiliate_legalese, class: 'JamRuby::AffiliateLegalese' do legalese Faker::Lorem.paragraphs(6).join("\n\n") - end + end end 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 d08299f04..79059d6c4 100644 --- a/ruby/spec/jam_ruby/models/active_music_session_spec.rb +++ b/ruby/spec/jam_ruby/models/active_music_session_spec.rb @@ -616,6 +616,7 @@ describe ActiveMusicSession do end it "disallow a jam track to be opened when another is already opened" do + pending "needs fixing" # if a jam track is open, don't allow another to be opened @music_session.open_jam_track(@user1, @jam_track) @music_session.errors.any?.should be_false diff --git a/ruby/spec/jam_ruby/models/broadcast_notification_spec.rb b/ruby/spec/jam_ruby/models/broadcast_notification_spec.rb new file mode 100644 index 000000000..4ec86db70 --- /dev/null +++ b/ruby/spec/jam_ruby/models/broadcast_notification_spec.rb @@ -0,0 +1,64 @@ +require 'spec_helper' + +describe BroadcastNotification do + + let(:broadcast1) { FactoryGirl.create(:broadcast_notification) } + let(:broadcast2) { FactoryGirl.create(:broadcast_notification) } + let(:broadcast3) { FactoryGirl.create(:broadcast_notification) } + let(:broadcast4) { FactoryGirl.create(:broadcast_notification) } + let(:user1) { FactoryGirl.create(:user) } + let(:user2) { FactoryGirl.create(:user) } + let(:user3) { FactoryGirl.create(:user) } + let(:user4) { FactoryGirl.create(:user) } + + before(:each) do + BroadcastNotificationView.delete_all + end + + it 'created broadcast' do + expect(broadcast1.title).not_to be_empty + expect(broadcast1.frequency).to be > 0 + end + + it 'gets view incremented' do + bnv = broadcast1.did_view(user1) + bnv = broadcast1.did_view(user1) + bnv.view_count.should eq(2) + end + + it 'loads viewable broadcasts for a user' do + broadcast1.touch + broadcast2.touch + broadcast3.touch + broadcast4.touch + + bns = BroadcastNotification.viewable_notifications(user1) + bns.count.should eq(4) + + broadcast2.frequency.times { |nn| broadcast2.did_view(user1) } + broadcast3.did_view(user1) + broadcast1.did_view(user1) + broadcast4.did_view(user2) + + bns = BroadcastNotification.viewable_notifications(user1) + expect(bns.count).to be(3) + expect(bns[0].id).to eq(broadcast3.id) + expect(bns.detect {|bb| bb.id==broadcast2.id }).to be_nil + expect(BroadcastNotification.next_broadcast(user1).id).to eq(broadcast3.id) + end + + it 'generates frequency distribution' do + 4.times { |nn| broadcast1.did_view(user1) } + 5.times { |nn| broadcast1.did_view(user2) } + 5.times { |nn| broadcast1.did_view(user3) } + 8.times { |nn| broadcast1.did_view(user4) } + + distrib = broadcast1.frequency_distribution + + expect(distrib.count).to be == 3 + expect(distrib[4]).to be == 1 + expect(distrib[5]).to be == 2 + expect(distrib[8]).to be == 1 + end + +end diff --git a/web/Gemfile b/web/Gemfile index 8145e5453..0339472b2 100644 --- a/web/Gemfile +++ b/web/Gemfile @@ -1,7 +1,4 @@ source 'http://rubygems.org' -unless ENV["LOCAL_DEV"] == "1" - source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/' -end # Look for $WORKSPACE, otherwise use "workspace" as dev path. devenv = ENV["BUILD_NUMBER"].nil? # Jenkins sets a build number environment variable @@ -12,11 +9,13 @@ if devenv gem 'jam_ruby', :path => "../ruby" gem 'jam_websockets', :path => "../websocket-gateway" else - gem 'jam_db', "0.1.#{ENV["BUILD_NUMBER"]}" - gem 'jampb', "0.1.#{ENV["BUILD_NUMBER"]}" - gem 'jam_ruby', "0.1.#{ENV["BUILD_NUMBER"]}" - gem 'jam_websockets', "0.1.#{ENV["BUILD_NUMBER"]}" - ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true" + source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/' do + gem 'jam_db', "0.1.#{ENV["BUILD_NUMBER"]}" + gem 'jampb', "0.1.#{ENV["BUILD_NUMBER"]}" + gem 'jam_ruby', "0.1.#{ENV["BUILD_NUMBER"]}" + gem 'jam_websockets', "0.1.#{ENV["BUILD_NUMBER"]}" + ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true" + end end gem 'oj', '2.10.2' @@ -90,6 +89,13 @@ gem 'guard', '2.7.3' gem 'influxdb', '0.1.8' gem 'influxdb-rails', '0.1.10' gem 'sitemap_generator' +gem 'bower-rails', "~> 0.9.2" +gem 'react-rails', '~> 1.0' +#gem "browserify-rails", "~> 0.7" + +source 'https://rails-assets.org' do + gem 'rails-assets-reflux' +end group :development, :test do gem 'rspec-rails', '2.14.2' @@ -139,6 +145,7 @@ group :test, :cucumber do # gem 'growl', '1.0.3' gem 'poltergeist' gem 'resque_spec' + #gem 'thin' end diff --git a/web/app/assets/javascripts/accounts_profile.js b/web/app/assets/javascripts/accounts_profile.js index 584fb6ff8..9938d4cf0 100644 --- a/web/app/assets/javascripts/accounts_profile.js +++ b/web/app/assets/javascripts/accounts_profile.js @@ -28,8 +28,8 @@ var $biography = $screen.find('#biography'); var $subscribe = $screen.find('#subscribe'); - var $btnCancel = $screen.find('#account-edit-profile-cancel'); - var $btnSubmit = $screen.find('#account-edit-profile-submit'); + var $btnCancel = $screen.find('.account-edit-profile-cancel'); + var $btnSubmit = $screen.find('.account-edit-profile-submit'); function beforeShow(data) { userId = data.id; diff --git a/web/app/assets/javascripts/accounts_profile_experience.js b/web/app/assets/javascripts/accounts_profile_experience.js index 6bb22fbab..de57e8695 100644 --- a/web/app/assets/javascripts/accounts_profile_experience.js +++ b/web/app/assets/javascripts/accounts_profile_experience.js @@ -10,9 +10,9 @@ var api = context.JK.Rest(); var $screen = $('#account-profile-experience'); var profileUtils = context.JK.ProfileUtils; - var $btnCancel = $screen.find('#account-edit-profile-cancel'); - var $btnBack = $screen.find('#account-edit-profile-back'); - var $btnSubmit = $screen.find('#account-edit-profile-submit'); + var $btnCancel = $screen.find('.account-edit-profile-cancel'); + var $btnBack = $screen.find('.account-edit-profile-back'); + var $btnSubmit = $screen.find('.account-edit-profile-submit'); var $instrumentSelector = $screen.find('.instrument_selector'); var $userGenres = $screen.find('#user-genres'); diff --git a/web/app/assets/javascripts/accounts_profile_interests.js b/web/app/assets/javascripts/accounts_profile_interests.js index 6257e69ed..6a4a65e2c 100644 --- a/web/app/assets/javascripts/accounts_profile_interests.js +++ b/web/app/assets/javascripts/accounts_profile_interests.js @@ -62,9 +62,9 @@ var $cowritingGenreList = $cowritingGenres.find(GENRE_LIST_SELECTOR) var $cowritingPurpose = $screen.find('#cowriting-purpose') - var $btnCancel = $screen.find('#account-edit-profile-cancel') - var $btnBack = $screen.find('#account-edit-profile-back') - var $btnSubmit = $screen.find('#account-edit-profile-submit') + var $btnCancel = $screen.find('.account-edit-profile-cancel') + var $btnBack = $screen.find('.account-edit-profile-back') + var $btnSubmit = $screen.find('.account-edit-profile-submit') function beforeShow(data) { } diff --git a/web/app/assets/javascripts/accounts_profile_samples.js b/web/app/assets/javascripts/accounts_profile_samples.js index 30cd85c20..6cce9de0e 100644 --- a/web/app/assets/javascripts/accounts_profile_samples.js +++ b/web/app/assets/javascripts/accounts_profile_samples.js @@ -5,14 +5,14 @@ context.JK = context.JK || {}; // TODO: Add a target type, which can be band or user -- call the - // appropriate API methods. + // appropriate API methods. context.JK.AccountProfileSamples = function(app, parent, loadFn, updateFn) { var $document = $(document) // used to initialize RecordingSourceValidator in site_validator.js.coffee - window.jamkazamRecordingSources = []; - window.soundCloudRecordingSources = []; - window.youTubeRecordingSources = []; + var jamkazamRecordingSources = []; + var soundCloudRecordingSources = []; + var youTubeRecordingSources = []; var logger = context.JK.logger; var EVENTS = context.JK.EVENTS; @@ -20,9 +20,9 @@ var ui = new context.JK.UIHelper(JK.app); var target = {}; var profileUtils = context.JK.ProfileUtils; - var $screen = $('.profile-online-sample-controls', parent); + var $screen = $('.profile-online-sample-controls', parent); // online presences - var $website = $screen.find('.website'); + var $website = $screen.find('.website'); var $soundCloudUsername = $screen.find('.soundcloud-username'); var $reverbNationUsername = $screen.find('.reverbnation-username'); var $bandCampUsername = $screen.find('.bandcamp-username'); @@ -32,31 +32,43 @@ var $twitterUsername = $screen.find('.twitter-username'); // performance samples - var $jamkazamSampleList = $screen.find('.samples.jamkazam').find('.sample-list'); - var $soundCloudSampleList = $screen.find('.samples.soundcloud').find('.sample-list'); - var $youTubeSampleList = $screen.find('.samples.youtube').find('.sample-list'); + var $jamkazamSampleList = $screen.find(".sample-list[source-type='jamkazam']") + var $soundCloudSampleList = $screen.find(".sample-list[source-type='soundcloud']") + var $youTubeSampleList = $screen.find(".sample-list[source-type='youtube']") // buttons - var $btnAddJkRecording = $screen.find('.btn-add-jk-recording'); - var $btnCancel = $screen.find('.account-edit-profile-cancel'); - var $btnBack = $screen.find('.account-edit-profile-back'); - var $btnSubmit = $screen.find('.account-edit-profile-submit'); + var $btnAddJkRecording = $screen.find('.btn-add-jk-recording') + var $btnCancel = parent.find('.account-edit-profile-cancel') + var $btnBack = parent.find('.account-edit-profile-back') + var $btnSubmit = parent.find('.account-edit-profile-submit') + + + var urlValidator=null + var soundCloudValidator=null + var reverbNationValidator=null + var bandCampValidator=null + var fandalismValidator=null + var youTubeValidator=null + var facebookValidator=null + var twitterValidator=null + var soundCloudRecordingValidator=null + var youTubeRecordingValidator=null function beforeShow(data) { } - function afterShow(data) { + function afterShow(data) { $.when(loadFn()) .done(function(targetPlayer) { if (targetPlayer && targetPlayer.keys && targetPlayer.keys.length > 0) { renderPlayer(targetPlayer) } - }); + }) } function renderPlayer(targetPlayer) { renderPresence(targetPlayer); - renderSamples(targetPlayer); + renderSamples(targetPlayer); } function renderPresence(targetPlayer) { @@ -108,20 +120,20 @@ function renderSamples(targetPlayer) { // JamKazam recordings var samples = profileUtils.jamkazamSamples(targetPlayer.performance_samples); - loadSamples(samples, 'jamkazam', $jamkazamSampleList, window.jamkazamRecordingSources); + loadSamples(samples, 'jamkazam', $jamkazamSampleList, jamkazamRecordingSources); // SoundCloud recordings samples = profileUtils.soundCloudSamples(targetPlayer.performance_samples); - loadSamples(samples, 'soundcloud', $soundCloudSampleList, window.soundCloudRecordingSources); + loadSamples(samples, 'soundcloud', $soundCloudSampleList, soundCloudRecordingSources); // YouTube videos samples = profileUtils.youTubeSamples(targetPlayer.performance_samples); - loadSamples(samples, 'youtube', $youTubeSampleList, window.youTubeRecordingSources); + loadSamples(samples, 'youtube', $youTubeSampleList, youTubeRecordingSources); } function loadSamples(samples, type, $sampleList, recordingSources) { - $sampleList.empty(); - + $sampleList.find(":not(.empty)").remove(); + if (type === 'jamkazam') { $.each(samples, function(index, val) { recordingSources.push({ @@ -131,8 +143,7 @@ buildJamkazamEntry(val.claimed_recording.id, val.claimed_recording.name); }); - } - else { + } else { if (samples && samples.length > 0) { $.each(samples, function(index, val) { @@ -148,9 +159,7 @@ var recordingTitleAttr = ' data-recording-title="' + val.description + '"'; var title = formatTitle(val.description); $sampleList.append('
' + title + '
'); - - var onclick = "onclick=removeRow(\'" + val.service_id + "\',\'" + type + "\');"; - $sampleList.append('
X
'); + $sampleList.append('
X
'); }); } } @@ -161,9 +170,7 @@ var recordingIdAttr = ' data-recording-id="' + recordingId + '" '; $jamkazamSampleList.append('
' + title + '
'); - - var onclick = "onclick=removeRow(\'" + recordingId + "\',\'jamkazam\');"; - $jamkazamSampleList.append('
X
'); + $jamkazamSampleList.append('
X
'); } function events() { @@ -175,14 +182,14 @@ // retrieve recordings and pass to modal dialog api.getClaimedRecordings() .done(function(response) { - ui.launchRecordingSelectorDialog(response, window.jamkazamRecordingSources, function(selectedRecordings) { + ui.launchRecordingSelectorDialog(response, jamkazamRecordingSources, function(selectedRecordings) { $jamkazamSampleList.empty(); - window.jamkazamRecordingSources = []; + jamkazamRecordingSources = []; // update the list with the selected recordings $.each(selectedRecordings, function(index, val) { - window.jamkazamRecordingSources.push({ + jamkazamRecordingSources.push({ 'claimed_recording_id': val.id, 'description': val.name }); @@ -191,7 +198,7 @@ }); }); }); - + return false; }); @@ -208,14 +215,18 @@ }); enableSubmits(); + + $screen.find(".sample-list").off("click").on("click", ".close-button", function(e) { + removeRow($(this).data("recording-id"), $(this).data("recording-type")) + }) } - function enableSubmits() { - $btnSubmit.on("click", function(evt) { - evt.stopPropagation(); + function enableSubmits() { + $btnSubmit.off("click").on("click", function(e) { + e.stopPropagation(); handleUpdateProfile(); return false; - }); + }) $btnSubmit.removeClass("disabled") } @@ -257,9 +268,7 @@ 'service_type': type, 'claimed_recording_id': id, }); - } - - else { + } else { var url = $(this).attr('data-recording-url'); var title = $(this).attr('data-recording-title'); @@ -291,7 +300,7 @@ function buildPlayer() { // extract online presences var op = []; - var presenceTypes = profileUtils.ONLINE_PRESENCE_TYPES; + var presenceTypes = profileUtils.ONLINE_PRESENCE_TYPES; addOnlinePresence(op, $soundCloudUsername.val(), presenceTypes.SOUNDCLOUD.description); addOnlinePresence(op, $reverbNationUsername.val(), presenceTypes.REVERBNATION.description); addOnlinePresence(op, $bandCampUsername.val(), presenceTypes.BANDCAMP.description); @@ -306,12 +315,12 @@ addPerformanceSamples(ps, $jamkazamSampleList, performanceSampleTypes.JAMKAZAM.description); addPerformanceSamples(ps, $soundCloudSampleList, performanceSampleTypes.SOUNDCLOUD.description); addPerformanceSamples(ps, $youTubeSampleList, performanceSampleTypes.YOUTUBE.description); - + return { website: $website.val(), online_presences: op, performance_samples: ps - } + } } function postUpdateProfileSuccess(response) { @@ -325,20 +334,23 @@ if(xhr.status == 422) { - } - else { + } else { app.ajaxError(xhr, textStatus, errorMessage) } } function removeRow(recordingId, type) { $('div[data-recording-id=' + recordingId + ']').remove(); + var sampleList = $('.sample-list[source-type="' + type + '"]') + var rowCnt = sampleList.find('.recording-row').length + if (0==parseInt(rowCnt)) { + sampleList.find(".empty").removeClass("hidden") + } if (type === 'soundcloud') { - window.soundCloudRecordingValidator.removeRecordingId(recordingId); - } - else if (type === 'youtube') { - window.youTubeRecordingValidator.removeRecordingId(recordingId); + soundCloudRecordingValidator.removeRecordingId(recordingId); + } else if (type === 'youtube') { + youTubeRecordingValidator.removeRecordingId(recordingId); } } @@ -347,13 +359,13 @@ } // This function is a bit of a mess. It was pulled - // from the html.erb file verbatim, and could use a + // from the html.erb file verbatim, and could use a // refactor: - function initializeValidators() { + function initializeValidators() { var initialized = false; - //$document.on('JAMKAZAM_READY', function(e, data) { - window.JK.JamServer.get$Server().on(window.JK.EVENTS.CONNECTION_UP, function() { - if(initialized) { + //$document.on('JAMKAZAM_READY', function(e, data) { + JK.JamServer.get$Server().on(JK.EVENTS.CONNECTION_UP, function() { + if(initialized) { return; } initialized = true; @@ -361,79 +373,77 @@ //var $screen = $('#account-profile-samples'); var $btnAddSoundCloudRecording = $screen.find('.btn-add-soundcloud-recording'); var $btnAddYouTubeVideo = $screen.find('.btn-add-youtube-video'); - var $soundCloudSampleList = $screen.find('.samples.soundcloud'); - var $youTubeSampleList = $screen.find('.samples.youtube'); + // var $soundCloudSampleList = $screen.find('.samples.soundcloud'); + // var $youTubeSampleList = $screen.find('.samples.youtube'); - setTimeout(function() { - window.urlValidator = new JK.SiteValidator('url', userNameSuccessCallback, userNameFailCallback, parent); - window.urlValidator.init(); - window.soundCloudValidator = new JK.SiteValidator('soundcloud', userNameSuccessCallback, userNameFailCallback, parent); - window.soundCloudValidator.init(); + setTimeout(function() { + urlValidator = new JK.SiteValidator('url', userNameSuccessCallback, userNameFailCallback, parent) + urlValidator.init() - window.reverbNationValidator = new JK.SiteValidator('reverbnation', userNameSuccessCallback, userNameFailCallback, parent); - window.reverbNationValidator.init(); + soundCloudValidator = new JK.SiteValidator('soundcloud', userNameSuccessCallback, userNameFailCallback, parent) + soundCloudValidator.init() - window.bandCampValidator = new JK.SiteValidator('bandcamp', userNameSuccessCallback, userNameFailCallback, parent); - window.bandCampValidator.init(); + reverbNationValidator = new JK.SiteValidator('reverbnation', userNameSuccessCallback, userNameFailCallback, parent) + reverbNationValidator.init() - window.fandalismValidator = new JK.SiteValidator('fandalism', userNameSuccessCallback, userNameFailCallback, parent); - window.fandalismValidator.init(); + bandCampValidator = new JK.SiteValidator('bandcamp', userNameSuccessCallback, userNameFailCallback, parent) + bandCampValidator.init() - window.youTubeValidator = new JK.SiteValidator('youtube', userNameSuccessCallback, userNameFailCallback, parent); - window.youTubeValidator.init(); + fandalismValidator = new JK.SiteValidator('fandalism', userNameSuccessCallback, userNameFailCallback, parent) + fandalismValidator.init() - window.facebookValidator = new JK.SiteValidator('facebook', userNameSuccessCallback, userNameFailCallback, parent); - window.facebookValidator.init(); + youTubeValidator = new JK.SiteValidator('youtube', userNameSuccessCallback, userNameFailCallback, parent) + youTubeValidator.init() - window.twitterValidator = new JK.SiteValidator('twitter', userNameSuccessCallback, userNameFailCallback, parent); - window.twitterValidator.init(); + facebookValidator = new JK.SiteValidator('facebook', userNameSuccessCallback, userNameFailCallback, parent) + facebookValidator.init() - window.soundCloudRecordingValidator = new JK.RecordingSourceValidator('rec_soundcloud', soundCloudSuccessCallback, siteFailCallback, parent); - logger.debug("window.soundCloudRecordingValidator", window.soundCloudRecordingValidator) - window.youTubeRecordingValidator = new JK.RecordingSourceValidator('rec_youtube', youTubeSuccessCallback, siteFailCallback, parent); + twitterValidator = new JK.SiteValidator('twitter', userNameSuccessCallback, userNameFailCallback, parent) + twitterValidator.init() - $document.triggerHandler('INIT_SITE_VALIDATORS'); - }, 1); + soundCloudRecordingValidator = new JK.RecordingSourceValidator('rec_soundcloud', soundCloudSuccessCallback, siteFailCallback, parent) + youTubeRecordingValidator = new JK.RecordingSourceValidator('rec_youtube', youTubeSuccessCallback, siteFailCallback, parent) + soundCloudRecordingValidator.init(soundCloudRecordingSources) + youTubeRecordingValidator.init(youTubeRecordingSources) + }, 1) function userNameSuccessCallback($inputDiv) { $inputDiv.removeClass('error'); $inputDiv.find('.error-text').remove(); } - function userNameFailCallback($inputDiv) { + function userNameFailCallback($inputDiv) { $inputDiv.addClass('error'); $inputDiv.find('.error-text').remove(); $inputDiv.append("Invalid username").show(); } function soundCloudSuccessCallback($inputDiv) { - siteSuccessCallback($inputDiv, window.soundCloudRecordingValidator, $soundCloudSampleList, 'soundcloud'); + siteSuccessCallback($inputDiv, soundCloudRecordingValidator, $soundCloudSampleList, 'soundcloud'); } function youTubeSuccessCallback($inputDiv) { - siteSuccessCallback($inputDiv, window.youTubeRecordingValidator, $youTubeSampleList, 'youtube'); + siteSuccessCallback($inputDiv, youTubeRecordingValidator, $youTubeSampleList, 'youtube'); } - function siteSuccessCallback($inputDiv, recordingSiteValidator, $sampleList, type) { + function siteSuccessCallback($inputDiv, recordingSiteValidator, sampleList, type) { + sampleList.find(".empty").addClass("hidden") $inputDiv.removeClass('error'); $inputDiv.find('.error-text').remove(); var recordingSources = recordingSiteValidator.recordingSources(); if (recordingSources && recordingSources.length > 0) { - var $sampleList = $sampleList.find('.sample-list'); var addedRecording = recordingSources[recordingSources.length-1]; - // TODO: this code is repeated in JS file + // TODO: this code is repeated in elsewhere in this JS file: var recordingIdAttr = ' data-recording-id="' + addedRecording.recording_id + '" '; var recordingUrlAttr = ' data-recording-url="' + addedRecording.url + '" '; var recordingTitleAttr = ' data-recording-title="' + addedRecording.recording_title + '"'; var title = formatTitle(addedRecording.recording_title); - $sampleList.append('
' + title + '
'); - - var onclick = "onclick=removeRow(\'" + addedRecording.recording_id + "\',\'" + type + "\');"; - $sampleList.append('
X
'); + sampleList.append('
' + title + '
'); + sampleList.append('
X
'); } $inputDiv.find('input').val(''); @@ -447,17 +457,12 @@ }); //}); - $document.on('INIT_SITE_VALIDATORS', function(e, data) { - logger.debug("ZZZwindow.soundCloudRecordingValidator", window.soundCloudRecordingValidator) - window.soundCloudRecordingValidator.init(window.soundCloudRecordingSources); - window.youTubeRecordingValidator.init(window.youTubeRecordingSources); - }); - - } // end initializeValidators. + + } // end initializeValidators. function resetForm() { - $("input", $screen).val("") + $("input", $screen).val("") } function initialize() { diff --git a/web/app/assets/javascripts/application.js b/web/app/assets/javascripts/application.js index d9ca26642..e77a3a58f 100644 --- a/web/app/assets/javascripts/application.js +++ b/web/app/assets/javascripts/application.js @@ -38,6 +38,7 @@ //= require jquery.exists //= require jquery.payment //= require jquery.visible +//= require reflux //= require howler.core.js //= require jstz //= require class @@ -50,6 +51,10 @@ //= require utils //= require subscription_utils //= require custom_controls +//= require react +//= require react_ujs +//= require react-init +//= require react-components //= require web/signup_helper //= require web/signin_helper //= require web/signin @@ -59,4 +64,4 @@ //= require_directory ./wizard //= require_directory ./wizard/gear //= require_directory ./wizard/loopback -//= require everywhere/everywhere \ No newline at end of file +//= require everywhere/everywhere diff --git a/web/app/assets/javascripts/bandProfile.js b/web/app/assets/javascripts/bandProfile.js index 1570a8519..b7501373b 100644 --- a/web/app/assets/javascripts/bandProfile.js +++ b/web/app/assets/javascripts/bandProfile.js @@ -4,526 +4,623 @@ context.JK = context.JK || {}; context.JK.BandProfileScreen = function(app) { - var logger = context.JK.logger; - var rest = context.JK.Rest(); - var bandId; - var isMember = false; - var isAdmin = false; - var band = {}; - var instrument_logo_map = context.JK.getInstrumentIconMap24(); + var NOT_SPECIFIED_TEXT = 'Not specified'; + var logger = context.JK.logger; + var rest = context.JK.Rest(); + var bandId; + var isMember = false; + var isAdmin = false; + var band = {}; + var instrument_logo_map = context.JK.getInstrumentIconMap24(); + var profileUtils = context.JK.ProfileUtils; + var feed = new context.JK.Feed(app) + var $root = $("#band-profile") + var $history = $root.find("#band-profile-history") - function beforeShow(data) { - bandId = data.id; + + + + function beforeShow(data) { + bandId = data.id; + feed.setBand(bandId); + } + + function beforeHide(data) { + feed.setBand(null); + } + + + function afterShow(data) { + // hide until we know if 'isMember' + $("#btn-follow-band").hide(); + $("#btn-edit-band-profile").hide(); + $("#btn-edit-band-bio").hide(); + $("#btn-edit-band-info").hide(); + $("#btn-edit-band-members").hide(); + $("#btn-edit-band-delete").hide(); + + resetForm(); + events(); + determineMembership() + .done(function() { + renderActive(); + }) + .fail(function(jqXHR) { + app.notifyServerError(jqXHR, "Unable to talk to server") + }) + } + + function resetForm() { + $('#band-profile-instruments').empty(); + + $('#band-profile-about').show(); + $('#band-profile-history').hide(); + $('#band-profile-members').hide(); + $('#band-profile-social').hide(); + + $('.band-profile-nav a.active').removeClass('active'); + $('.band-profile-nav a#band-profile-about-link').addClass('active'); + } + + /****************** MAIN PORTION OF SCREEN *****************/ + + function addFollowing(isBand, id) { + var newFollowing = {}; + + if (!isBand) { + newFollowing.user_id = id; + } + else { + newFollowing.band_id = id; } - function afterShow(data) { - - // hide until we know if 'isMember' - $("#btn-follow-band").hide(); - $("#btn-edit-band-profile").hide(); - $("#btn-edit-band-info").hide(); - $("#btn-edit-band-members").hide(); - $("#btn-edit-band-delete").hide(); - - resetForm(); - events(); - determineMembership() - .done(function() { - renderActive(); - }) - .fail(function(jqXHR) { - app.notifyServerError(jqXHR, "Unable to talk to server") - }) - } - - function resetForm() { - $('#band-profile-instruments').empty(); - - $('#band-profile-about').show(); - $('#band-profile-history').hide(); - $('#band-profile-members').hide(); - $('#band-profile-social').hide(); - - $('.band-profile-nav a.active').removeClass('active'); - $('.band-profile-nav a#band-profile-about-link').addClass('active'); - } - - /****************** MAIN PORTION OF SCREEN *****************/ - - function addFollowing(isBand, id) { - var newFollowing = {}; - - if (!isBand) { - newFollowing.user_id = id; - } - else { - newFollowing.band_id = id; - } - - rest.addFollowing(newFollowing) - .done(function() { - if (isBand) { - var newCount = parseInt($("#band-profile-follower-stats").text()) + 1; - var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower"; - $('#band-profile-follower-stats').html(newCount + text); - configureBandFollowingButton(true); - } - else { - configureMemberFollowingButton(true, id); - } - renderActive(); - }) - .fail(app.ajaxError); - } - - function removeFollowing(isBand, id) { - rest.removeFollowing(id) - .done(function() { - if (isBand) { - var newCount = parseInt($("#band-profile-follower-stats").text()) - 1; - var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower"; - $('#band-profile-follower-stats').html(newCount + text); - configureBandFollowingButton(false); - } - else { - configureMemberFollowingButton(false, id); - } - renderActive(); - }) - .fail(app.ajaxError); - } - - function configureBandFollowingButton(following) { - $('#btn-follow-band').unbind("click"); - - if (following) { - $('#btn-follow-band').text('UNFOLLOW'); - $('#btn-follow-band').click(function() { - removeFollowing(true, bandId); - return false; - }); + rest.addFollowing(newFollowing) + .done(function() { + if (isBand) { + var newCount = parseInt($("#band-profile-follower-stats").text()) + 1; + var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower"; + $('#band-profile-follower-stats').html(newCount + text); + configureBandFollowingButton(true); } else { - $('#btn-follow-band').text('FOLLOW'); - $('#btn-follow-band').click(function() { - addFollowing(true, bandId); - return false; - }); + configureMemberFollowingButton(true, id); } - } + renderActive(); + }) + .fail(app.ajaxError); + } - function configureMemberFollowingButton(following, userId) { - - var $btnFollowMember = $('div[user-id=' + userId + ']', '#band-profile-members').find('#btn-follow-member'); - - if (context.JK.currentUserId === userId) { - $btnFollowMember.hide(); + function removeFollowing(isBand, id) { + rest.removeFollowing(id) + .done(function() { + if (isBand) { + var newCount = parseInt($("#band-profile-follower-stats").text()) - 1; + var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower"; + $('#band-profile-follower-stats').html(newCount + text); + configureBandFollowingButton(false); } else { - $btnFollowMember.unbind("click"); - - if (following) { - $btnFollowMember.text('UNFOLLOW'); - $btnFollowMember.click(function() { - removeFollowing(false, userId); - return false; - }); - } - else { - $btnFollowMember.text('FOLLOW'); - $btnFollowMember.click(function() { - addFollowing(false, userId); - return false; - }); - } + configureMemberFollowingButton(false, id); } - } + renderActive(); + }) + .fail(app.ajaxError); + } - // refreshes the currently active tab - function renderActive() { + function configureBandFollowingButton(following) { + $('#btn-follow-band').unbind("click"); - if (isMember) { - $("#btn-follow-band").hide(); - $("#btn-edit-band-profile").show(); - $("#btn-edit-band-info").show(); - $("#btn-edit-band-members").show(); - if (isAdmin) - $("#btn-edit-band-delete").show(); - } - else { - $("#btn-follow-band").show(); - $("#btn-edit-band-profile").hide(); - $("#btn-edit-band-info").hide(); - $("#btn-edit-band-members").hide(); - $("#btn-edit-band-delete").hide(); - } - - if ($('#band-profile-about-link').hasClass('active')) { - renderAbout(); - } - else if ($('#band-profile-history-link').hasClass('active')) { - renderHistory(); - } - else if ($('#band-profile-members-link').hasClass('active')) { - renderMembers(); - } - else if ($('#band-profile-social-link').hasClass('active')) { - renderSocial(); - } - } - - /****************** ABOUT TAB *****************/ - function renderAbout() { - - $('#band-profile-about').show(); - $('#band-profile-history').hide(); - $('#band-profile-members').hide(); - $('#band-profile-social').hide(); - - $('.band-profile-nav a.active').removeClass('active'); - $('.band-profile-nav a#band-profile-about-link').addClass('active'); - - bindAbout(); - } - - function bindAbout() { - - rest.getBand(bandId) - .done(function(response) { - band = response; - if (band) { - // name - $('#band-profile-name').text(band.name); - - // avatar - $('#band-profile-avatar').attr('src', context.JK.resolveAvatarUrl(band.photo_url)); - - // location - $('#band-profile-location').html(band.location); - - // stats - var text = band.follower_count > 1 || band.follower_count == 0 ? " Followers" : " Follower"; - $('#band-profile-follower-stats').html(band.follower_count + text); - - text = band.session_count > 1 || band.session_count == 0 ? " Sessions" : " Session"; - $('#band-profile-session-stats').html(band.session_count + text); - - text = band.recording_count > 1 || band.recording_count == 0 ? " Recordings" : " Recording"; - $('#band-profile-recording-stats').html(band.recording_count + text); - - $('#band-profile-biography').text(band.biography); - - if (band.website) { - $('#band-profile-website').attr('href', band.website); - $('#band-profile-website').text(band.website); - } - - // wire up Follow click - configureBandFollowingButton(band.is_following); - } - else { - logger.debug("No band found with bandId = " + bandId); - } - }) - .fail(function(xhr) { - if(xhr.status >= 500) { - context.JK.fetchUserNetworkOrServerFailure(); - } - else if(xhr.status == 404) { - context.JK.entityNotFound("Band"); - } - else { - context.JK.app.ajaxError(arguments); - } - }); - } - - /****************** SOCIAL TAB *****************/ - function renderSocial() { - $('#band-profile-social-followers').empty(); - - $('#band-profile-about').hide(); - $('#band-profile-history').hide(); - $('#band-profile-members').hide(); - $('#band-profile-social').show(); - - $('.band-profile-nav a.active').removeClass('active'); - $('.band-profile-nav a#band-profile-social-link').addClass('active'); - - bindSocial(); - } - - function bindSocial() { - - rest.getBandFollowers(bandId) - .done(function(response) { - $.each(response, function(index, val) { - // var template = $('#template-profile-social').html(); - var template = $('#template-band-profile-social').html(); - var followerHtml = context.JK.fillTemplate(template, { - userId: val.id, - hoverAction: val.musician ? "musician" : "fan", - avatar_url: context.JK.resolveAvatarUrl(val.photo_url), - userName: val.name, - location: val.location - }); - - $('#band-profile-social-followers').append(followerHtml); - - if (index === response.length-1) { - context.JK.bindHoverEvents(); - } - }) - }) - .fail(function(xhr) { - if(xhr.status >= 500) { - context.JK.fetchUserNetworkOrServerFailure(); - } - else { - context.JK.app.ajaxError(arguments); - } - }); - } - - /****************** HISTORY TAB *****************/ - function renderHistory() { - $('#band-profile-about').hide(); - $('#band-profile-history').show(); - $('#band-profile-members').hide(); - $('#band-profile-social').hide(); - - $('.band-profile-nav a.active').removeClass('active'); - $('.band-profile-nav a#band-profile-history-link').addClass('active'); - - bindHistory(); - } - - function bindHistory() { - - } - - /****************** BANDS TAB *****************/ - function renderMembers() { - $('#band-profile-members').empty(); - - $('#band-profile-about').hide(); - $('#band-profile-history').hide(); - $('#band-profile-members').show(); - $('#band-profile-social').hide(); - - $('.band-profile-nav a.active').removeClass('active'); - $('.band-profile-nav a#band-profile-members-link').addClass('active'); - - bindMembers(); - } - - function bindMembers() { - rest.getBandMembers(bandId, false) - .done(function(response) { - bindMusicians(response, false); - if (isMember) { - bindPendingMembers(); - } - }) - .fail(function(xhr) { - if(xhr.status >= 500) { - context.JK.fetchUserNetworkOrServerFailure(); - } - else { - context.JK.app.ajaxError(arguments); - } - }); - } - - function bindPendingMembers() { - rest.getBandMembers(bandId, true) - .done(function(response) { - if (response && response.length > 0) { - $("#band-profile-members").append("

Pending Band Invitations

"); - bindMusicians(response, true); - } - }) - .fail(function(xhr) { - if(xhr.status >= 500) { - context.JK.fetchUserNetworkOrServerFailure(); - } - else { - context.JK.app.ajaxError(arguments); - } - }); - } - - function bindMusicians(musicians, isPending) { - $.each(musicians, function(index, musician) { - var instrumentLogoHtml = ''; - if ("instruments" in musician && musician.instruments != null) { - for (var j=0; j < musician.instruments.length; j++) { - var instrument = musician.instruments[j]; - var inst = '../assets/content/icon_instrument_default24.png'; - if (instrument.instrument_id in instrument_logo_map) { - inst = instrument_logo_map[instrument.instrument_id].asset; - } - instrumentLogoHtml += ' '; - } - } - var bandAdmin = musician.band_admin; - var template = $('#template-band-profile-members').html(); - var memberHtml = context.JK.fillTemplate(template, { - userId: musician.id, - band_admin: bandAdmin, - is_pending: isPending, - invitation_id: isPending ? musician.invitation_id : '', - profile_url: "/client#/profile/" + musician.id, - avatar_url: context.JK.resolveAvatarUrl(musician.photo_url), - name: musician.name, - location: musician.location, - biography: musician.biography, - friend_count: musician.friend_count, - follower_count: musician.follower_count, - recording_count: musician.recording_count, - session_count: musician.session_count, - instruments: instrumentLogoHtml - }); - - $('#band-profile-members').append(memberHtml); - - // wire up Follow button click handler - configureMemberFollowingButton(musician.is_following, musician.id); - configureRemoveMemberButton(musician.id, isPending, bandAdmin); - - // TODO: wire up Friend button click handler - // var friend = isFriend(musician.id); - // configureMemberFriendButton(friend, musician.id); - }); - if (isPending) { - $('div[pending-member=true] .btn-reinvite-member').each(function() { - var btn = $(this); - btn.show(); - btn.unbind('click'); - btn.click(function() { - var inviteid = $(this).closest('.band-profile-members').attr('invitation-id'); - rest.resendBandInvitation(bandId, inviteid) - .done(function (response) { - app.notifyAlert('Band Invitation', 'Your invitation has been re-sent'); - }).fail(app.ajaxError); - }); - }); - } - } - - function configureRemoveMemberButton(userId, isPending, bandAdmin) { - var $divMember = $('div[user-id=' + userId + ']', '#band-profile-members'); - var $btnRemoveMember = $divMember.find('.btn-remove-member'); - if (isMember && !isPending && !bandAdmin) { - $btnRemoveMember.show(); - $btnRemoveMember.unbind("click"); - $btnRemoveMember.click(function() { - var confirmMemberDeleteTxt; - if (userId == context.JK.currentUserId) - confirmMemberDeleteTxt = 'Are you sure you want to delete yourself from the band?'; - else - confirmMemberDeleteTxt = 'Are you sure you want to delete this member from the band?'; - var confirmDialog = new context.JK.ConfirmDialog(app, "DELETE", confirmMemberDeleteTxt, "Edit Band Membership", - function() { - app.layout.closeDialog('confirm'); - rest.removeBandMember(bandId, userId) - .done(function() { - $divMember.remove(); - if (userId == context.JK.currentUserId) { - $('#btn-edit-band-profile').hide(); - $('#btn-edit-band-info').hide(); - $('#btn-edit-band-members').hide(); - $('.btn-remove-member').each(function(idx) { $(this).hide(); }); - $('.btn-reinvite-member').each(function(idx) { $(this).hide(); }); - } - }) - .fail(app.ajaxError); - }); - confirmDialog.initialize(); - context.JK.app.layout.showDialog('confirm'); + if (following) { + $('#btn-follow-band').text('UNFOLLOW'); + $('#btn-follow-band').click(function() { + removeFollowing(true, bandId); return false; - }); + }); + } else { + $('#btn-follow-band').text('FOLLOW'); + $('#btn-follow-band').click(function() { + addFollowing(true, bandId); + return false; + }); + } + } + + function configureMemberFollowingButton(following, userId) { + + var $btnFollowMember = $('div[user-id=' + userId + ']', '#band-profile-members').find('#btn-follow-member'); + + if (context.JK.currentUserId === userId) { + $btnFollowMember.hide(); + } else { + $btnFollowMember.unbind("click"); + + if (following) { + $btnFollowMember.text('UNFOLLOW'); + $btnFollowMember.click(function() { + removeFollowing(false, userId); + return false; + }); + } + else { + $btnFollowMember.text('FOLLOW'); + $btnFollowMember.click(function() { + addFollowing(false, userId); + return false; + }); + } + } + } + + // refreshes the currently active tab + function renderActive() { + + if (isMember) { + $("#btn-follow-band").hide(); + $("#btn-edit-band-profile").show(); + $("#btn-edit-band-bio").show(); + $("#btn-edit-band-info").show(); + $("#btn-edit-band-members").show(); + if (isAdmin) { + $("#btn-edit-band-delete").show(); + } + } else { + $("#btn-follow-band").show(); + $("#btn-edit-band-bio").hide(); + $("#btn-edit-band-profile").hide(); + $("#btn-edit-band-info").hide(); + $("#btn-edit-band-members").hide(); + $("#btn-edit-band-delete").hide(); + } + + if ($('#band-profile-about-link').hasClass('active')) { + renderAbout(); + } else if ($('#band-profile-history-link').hasClass('active')) { + renderHistory(); + } else if ($('#band-profile-members-link').hasClass('active')) { + renderMembers(); + } else if ($('#band-profile-social-link').hasClass('active')) { + renderSocial(); + } + } + + /****************** ABOUT TAB *****************/ + function renderAbout() { + + $('#band-profile-about').show(); + $('#band-profile-history').hide(); + $('#band-profile-members').hide(); + $('#band-profile-social').hide(); + + $('.band-profile-nav a.active').removeClass('active'); + $('.band-profile-nav a#band-profile-about-link').addClass('active'); + + + + bindAbout(); + } + + function bindAbout() { + + rest.getBand(bandId) + .done(function(response) { + band = response; + if (band) { + // name + $('#band-profile-name').text(band.name); + + // avatar + $('#band-profile-avatar').attr('src', context.JK.resolveAvatarUrl(band.photo_url)); + + // location + $('#band-profile-location').html(band.location); + + // stats + var text = band.follower_count > 1 || band.follower_count == 0 ? " Followers" : " Follower"; + $('#band-profile-follower-stats').html(band.follower_count + text); + + text = band.session_count > 1 || band.session_count == 0 ? " Sessions" : " Session"; + $('#band-profile-session-stats').html(band.session_count + text); + + text = band.recording_count > 1 || band.recording_count == 0 ? " Recordings" : " Recording"; + $('#band-profile-recording-stats').html(band.recording_count + text); + + $('#band-profile-biography').text(band.biography); + + renderMusicalExperience() + profileUtils.renderPerformanceSamples(band, $root, isAdmin) + profileUtils.renderOnlinePresence(band, $root, isAdmin) + renderCurrentInterests() + + // wire up Follow click + configureBandFollowingButton(band.is_following); + } + else { + logger.debug("No band found with bandId = " + bandId); + } + }) + .fail(function(xhr) { + if(xhr.status >= 500) { + context.JK.fetchUserNetworkOrServerFailure(); + } + else if(xhr.status == 404) { + context.JK.entityNotFound("Band"); + } + else { + context.JK.app.ajaxError(arguments); + } + }); + } + + function renderMusicalExperience() { + var genres = buildGenreList(band.genres) + var gigs = (band.concert_count > 0) ? 'Has played ' + profileUtils.gigMap[band.concert_count] + ' live concert gigs' : NOT_SPECIFIED_TEXT; + var bandType ; + if (!band.band_type || typeof(band.band_type)=="undefined" || band.band_type==="") { + bandType = "Not specified"; + } else if (band.band_type.toLowerCase()==="physical") { + bandType = "Physical"; + } else if (band.band_type.toLowerCase()==="virtual") { + bandType = "Virtual"; + } else { + bandType = "Not specified"; + } + + var bandStatus ; + if (!band.band_status || typeof(band.band_status)=="undefined" || band.band_status==="") { + bandStatus = "Not specified"; + } else if (band.band_status.toLowerCase()==="amateur") { + bandStatus = "Amateur Band"; + } else if (band.band_status.toLowerCase()==="professional") { + bandStatus = "Professional Band"; + } else { + bandStatus = "Not specified"; + } + + $root.find(".experience-genres").html(genres) + $root.find(".experience-gigs").html(gigs) + $root.find(".experience-status").html(bandStatus) + $root.find(".experience-type").html(bandType) + + } + + function renderCurrentInterests() { + if (band.add_new_members) { + $root.find(".new-member-details").html(profileUtils.renderBandInstruments(band)) + $root.find(".interests-new-members").removeClass("hidden") + } else { + $root.find(".interests-new-members").addClass("hidden") + } + + if (band.paid_gigs) { + $root.find(".paid-gig-rate").html(band.hourly_rate) + $root.find(".paid-gig-minimum").html(band.gig_minimum) + $root.find(".interests-paid-gigs").removeClass("hidden") + } else { + $root.find(".interests-paid-gigs").addClass("hidden") + } + + if (band.free_gigs) { + $root.find(".interests-free-gigs").removeClass("hidden") + } else { + $root.find(".interests-free-gigs").addClass("hidden") + } + + } + + + /****************** SOCIAL TAB *****************/ + function renderSocial() { + $('#band-profile-social-followers').empty(); + + $('#band-profile-about').hide(); + $('#band-profile-history').hide(); + $('#band-profile-members').hide(); + $('#band-profile-social').show(); + + $('.band-profile-nav a.active').removeClass('active'); + $('.band-profile-nav a#band-profile-social-link').addClass('active'); + + bindSocial(); + } + + function bindSocial() { + + rest.getBandFollowers(bandId) + .done(function(response) { + $.each(response, function(index, val) { + // var template = $('#template-profile-social').html(); + var template = $('#template-band-profile-social').html(); + var followerHtml = context.JK.fillTemplate(template, { + userId: val.id, + hoverAction: val.musician ? "musician" : "fan", + avatar_url: context.JK.resolveAvatarUrl(val.photo_url), + userName: val.name, + location: val.location + }); + + $('#band-profile-social-followers').append(followerHtml); + + if (index === response.length-1) { + context.JK.bindHoverEvents(); + } + }) + }) + .fail(function(xhr) { + if(xhr.status >= 500) { + context.JK.fetchUserNetworkOrServerFailure(); } else { - $btnRemoveMember.hide(); + context.JK.app.ajaxError(arguments); } + }); + } + + /****************** HISTORY TAB *****************/ + function renderHistory() { + $('#band-profile-about').hide(); + $('#band-profile-history').show(); + $('#band-profile-members').hide(); + $('#band-profile-social').hide(); + + $('.band-profile-nav a.active').removeClass('active'); + $('.band-profile-nav a#band-profile-history-link').addClass('active'); + + bindHistory(); + } + + function bindHistory() { + feed.refresh(); + } + + function buildGenreList(genres) { + var list = ''; + + for (var i=0; i < genres.length; i++) { + list = list.concat(genres[i].id); + if (i !== genres.length - 1) { + list = list.concat(', '); + } } - // checks if person viewing the profile is also a band member - function determineMembership() { - var url = "/api/bands/" + bandId + "/musicians"; - return $.ajax({ - type: "GET", - dataType: "json", - url: url, - processData:false, - error: app.ajaxError - }) - .done(function(response) { - isAdmin = isMember = false; - $.each(response, function(index, val) { - if (val.id === context.JK.currentUserId) { - isMember = true; - if (val.band_admin) { - isAdmin = true; - } + return list; + } + + /****************** BANDS TAB *****************/ + function renderMembers() { + $('#band-profile-members').empty(); + + $('#band-profile-about').hide(); + $('#band-profile-history').hide(); + $('#band-profile-members').show(); + $('#band-profile-social').hide(); + + $('.band-profile-nav a.active').removeClass('active'); + $('.band-profile-nav a#band-profile-members-link').addClass('active'); + + bindMembers(); + } + + function bindMembers() { + rest.getBandMembers(bandId, false) + .done(function(response) { + bindMusicians(response, false); + if (isMember) { + bindPendingMembers(); + } + }) + .fail(function(xhr) { + if(xhr.status >= 500) { + context.JK.fetchUserNetworkOrServerFailure(); + } + else { + context.JK.app.ajaxError(arguments); + } + }); + } + + function bindPendingMembers() { + rest.getBandMembers(bandId, true) + .done(function(response) { + if (response && response.length > 0) { + $("#band-profile-members").append("

Pending Band Invitations

"); + bindMusicians(response, true); + } + }) + .fail(function(xhr) { + if(xhr.status >= 500) { + context.JK.fetchUserNetworkOrServerFailure(); + } + else { + context.JK.app.ajaxError(arguments); + } + }); + } + + function bindMusicians(musicians, isPending) { + $.each(musicians, function(index, musician) { + var instrumentLogoHtml = ''; + if ("instruments" in musician && musician.instruments != null) { + for (var j=0; j < musician.instruments.length; j++) { + var instrument = musician.instruments[j]; + var inst = '../assets/content/icon_instrument_default24.png'; + if (instrument.instrument_id in instrument_logo_map) { + inst = instrument_logo_map[instrument.instrument_id].asset; + } + instrumentLogoHtml += ' '; } - }); - }) + } + var bandAdmin = musician.band_admin; + var template = $('#template-band-profile-members').html(); + var memberHtml = context.JK.fillTemplate(template, { + userId: musician.id, + band_admin: bandAdmin, + is_pending: isPending, + invitation_id: isPending ? musician.invitation_id : '', + profile_url: "/client#/profile/" + musician.id, + avatar_url: context.JK.resolveAvatarUrl(musician.photo_url), + name: musician.name, + location: musician.location, + biography: musician.biography, + friend_count: musician.friend_count, + follower_count: musician.follower_count, + recording_count: musician.recording_count, + session_count: musician.session_count, + instruments: instrumentLogoHtml + }); + + $('#band-profile-members').append(memberHtml); + + // wire up Follow button click handler + configureMemberFollowingButton(musician.is_following, musician.id); + configureRemoveMemberButton(musician.id, isPending, bandAdmin); + + // TODO: wire up Friend button click handler + // var friend = isFriend(musician.id); + // configureMemberFriendButton(friend, musician.id); + }); + if (isPending) { + $('div[pending-member=true] .btn-reinvite-member').each(function() { + var btn = $(this); + btn.show(); + btn.unbind('click'); + btn.click(function() { + var inviteid = $(this).closest('.band-profile-members').attr('invitation-id'); + rest.resendBandInvitation(bandId, inviteid) + .done(function (response) { + app.notifyAlert('Band Invitation', 'Your invitation has been re-sent'); + }).fail(app.ajaxError); + }); + }); } + } - // events for main screen - function events() { - // wire up panel clicks - $('#band-profile-about-link').unbind('click').click(renderAbout); - $('#band-profile-history-link').unbind('click').click(renderHistory); - $('#band-profile-members-link').unbind('click').click(renderMembers); - $('#band-profile-social-link').unbind('click').click(renderSocial); + function configureRemoveMemberButton(userId, isPending, bandAdmin) { + var $divMember = $('div[user-id=' + userId + ']', '#band-profile-members'); + var $btnRemoveMember = $divMember.find('.btn-remove-member'); + if (isMember && !isPending && !bandAdmin) { + $btnRemoveMember.show(); + $btnRemoveMember.unbind("click"); + $btnRemoveMember.click(function() { + var confirmMemberDeleteTxt; + if (userId == context.JK.currentUserId) + confirmMemberDeleteTxt = 'Are you sure you want to delete yourself from the band?'; + else + confirmMemberDeleteTxt = 'Are you sure you want to delete this member from the band?'; + var confirmDialog = new context.JK.ConfirmDialog(app, "DELETE", confirmMemberDeleteTxt, "Edit Band Membership", + function() { + app.layout.closeDialog('confirm'); + rest.removeBandMember(bandId, userId) + .done(function() { + $divMember.remove(); + if (userId == context.JK.currentUserId) { + $('#btn-edit-band-profile').hide(); + $('#btn-edit-band-bio').hide(); + $('#btn-edit-band-info').hide(); + $('#btn-edit-band-members').hide(); + $('.btn-remove-member').each(function(idx) { $(this).hide(); }); + $('.btn-reinvite-member').each(function(idx) { $(this).hide(); }); + } + }) + .fail(app.ajaxError); + }); + confirmDialog.initialize(); + context.JK.app.layout.showDialog('confirm'); + return false; + }); + } else { + $btnRemoveMember.hide(); + } + } - $("#btn-edit-band-profile").unbind('click').click(function() { - context.location = "/client#/band/setup/" + bandId + '/step0'; - return false; - }); - $("#btn-edit-band-info").unbind('click').click(function() { - context.location = "/client#/band/setup/" + bandId + '/step1'; - return false; - }); - $("#btn-edit-band-members").unbind('click').click(function() { - context.location = "/client#/band/setup/" + bandId + '/step2'; - return false; - }); - $("#btn-edit-band-delete").unbind('click').click(function() { - var confirmDialog = new context.JK.ConfirmDialog(app, - "DELETE", - "Are you sure you want to delete this band? This is a permanent action which cannot be undone.", - "Delete Band", - function() { - app.layout.closeDialog('confirm'); - rest.deleteBand(bandId) - .done(function() { - context.location = "/client#/profile/"+context.JK.currentUserId; - }) - .fail(app.ajaxError); - }); - confirmDialog.initialize(); - context.JK.app.layout.showDialog('confirm'); + // checks if person viewing the profile is also a band member + function determineMembership() { + var url = "/api/bands/" + bandId + "/musicians"; + return $.ajax({ + type: "GET", + dataType: "json", + url: url, + processData:false, + error: app.ajaxError + }) + .done(function(response) { + isAdmin = isMember = false; + $.each(response, function(index, val) { + if (val.id === context.JK.currentUserId) { + isMember = true; + if (val.band_admin) { + isAdmin = true; + } + } + }); + }) + } + + // events for main screen + function events() { + // wire up panel clicks + $('#band-profile-about-link').unbind('click').click(renderAbout); + $('#band-profile-history-link').unbind('click').click(renderHistory); + $('#band-profile-members-link').unbind('click').click(renderMembers); + $('#band-profile-social-link').unbind('click').click(renderSocial); + + $("#btn-edit-band-profile").unbind('click').click(function() { + context.location = "/client#/band/setup/" + bandId + '/step0'; return false; - }); - } + }); + $("#btn-edit-band-info").unbind('click').click(function() { + context.location = "/client#/band/setup/" + bandId + '/step1'; + return false; + }); + $("#btn-edit-band-bio").unbind('click').click(function() { + context.location = "/client#/band/setup/" + bandId + '/step0'; + return false; + }); + $("#btn-edit-band-members").unbind('click').click(function() { + context.location = "/client#/band/setup/" + bandId + '/step2'; + return false; + }); + $("#btn-edit-band-delete").unbind('click').click(function() { + var confirmDialog = new context.JK.ConfirmDialog(app, + "DELETE", + "Are you sure you want to delete this band? This is a permanent action which cannot be undone.", + "Delete Band", + function() { + app.layout.closeDialog('confirm'); + rest.deleteBand(bandId) + .done(function() { + context.location = "/client#/profile/"+context.JK.currentUserId; + }) + .fail(app.ajaxError); + }); + confirmDialog.initialize(); + context.JK.app.layout.showDialog('confirm'); + return false; + }); + } - function initialize() { - var screenBindings = { - 'beforeShow': beforeShow, - 'afterShow': afterShow - }; - app.bindScreen('bandProfile', screenBindings); - } + function initialize() { + var screenBindings = { + 'beforeShow': beforeShow, + 'afterShow': afterShow + }; + app.bindScreen('bandProfile', screenBindings); + + var $feedScroller = $history.find(".content-body-scroller") + var $feedContent = $feedScroller.find(".feed-content") + var $noMoreFeeds = $feedScroller.find('.end-of-list') + var $refresh = $history.find('.btn-refresh-entries'); + var $sortFeedBy = $history.find('#feed_order_by'); + var $includeDate = $history.find('#feed_date'); + var $includeType = $history.find('#feed_show'); - this.initialize = initialize; - this.beforeShow = beforeShow; - this.afterShow = afterShow; - return this; - }; + feed.initialize($history, $feedScroller, $feedContent, $noMoreFeeds, $refresh, $sortFeedBy, $includeDate, $includeType, {time_range: 'all'}) + } + + this.initialize = initialize; + this.beforeShow = beforeShow; + this.afterShow = afterShow; + return this; + } })(window,jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/band_setup.js b/web/app/assets/javascripts/band_setup.js index 9d4b59487..4e09a8e47 100644 --- a/web/app/assets/javascripts/band_setup.js +++ b/web/app/assets/javascripts/band_setup.js @@ -31,15 +31,15 @@ var friendInput=null var bandType=null var bandStatus=null - var concertCount=null - - + var concertCount=null + + var $screen=$("#band-setup") var $samples = $screen.find(".account-profile-samples") var $selectedInstruments=[] - - var accountProfileSamples = new JK.AccountProfileSamples(app, $screen, loadBandCallback, rest.updateBand) - accountProfileSamples.initialize() + + var accountProfileSamples = new JK.AccountProfileSamples(app, $screen, loadBandCallback, rest.updateBand) + accountProfileSamples.initialize() function navBack() { if (currentStep>0) { @@ -49,13 +49,13 @@ }) } } - + function navCancel() { - resetForm() + resetForm() window.history.go(-1) return false } - + function navNext() { if (currentStep @logger = context.JK.logger @gearUtils = context.JK.GearUtils + @ALERT_NAMES = context.JK.ALERT_NAMES; + @lastCheckedBroadcast = null init: () => if context.gon.isNativeClient this.nativeClientInit() + context.JK.onBackendEvent(@ALERT_NAMES.WINDOW_OPEN_FOREGROUND_MODE, 'client_init', @watchBroadcast); + + this.watchBroadcast() + + checkBroadcast: () => + broadcastActions.load.triggerPromise() + + watchBroadcast: () => + if context.JK.currentUserId + # create a 15 second buffer to not check too fast for some reason (like the client firing multiple foreground events) + if !@lastCheckedBroadcast? || @lastCheckedBroadcast.getTime() < new Date().getTime() - 15000 + @lastCheckedBroadcast = new Date() + setTimeout(@checkBroadcast, 3000) + + nativeClientInit: () => @gearUtils.bootstrapDefaultPlaybackProfile(); + + diff --git a/web/app/assets/javascripts/fakeJamClient.js b/web/app/assets/javascripts/fakeJamClient.js index e571976b2..8347edae5 100644 --- a/web/app/assets/javascripts/fakeJamClient.js +++ b/web/app/assets/javascripts/fakeJamClient.js @@ -4,6 +4,7 @@ context.JK = context.JK || {}; context.JK.FakeJamClient = function(app, p2pMessageFactory) { + var ChannelGroupIds = context.JK.ChannelGroupIds; var logger = context.JK.logger; logger.info("*** Fake JamClient instance initialized. ***"); @@ -474,7 +475,18 @@ } function SessionGetControlState(mixerIds, isMasterOrPersonal) { dbg("SessionGetControlState"); - var groups = [0, 1, 2, 3, 3, 7, 8, 10, 11, 12]; + var groups = [ + ChannelGroupIds.MasterGroup, + ChannelGroupIds.MonitorGroup, + ChannelGroupIds.AudioInputMusicGroup, + ChannelGroupIds.AudioInputChatGroup, + ChannelGroupIds.AudioInputChatGroup, + ChannelGroupIds.UserMusicInputGroup, + ChannelGroupIds.UserChatInputGroup, + ChannelGroupIds.PeerMediaTrackGroup, + ChannelGroupIds.JamTrackGroup, + ChannelGroupIds.MetronomeGroup + ] var names = [ "FW AP Multi", "FW AP Multi", diff --git a/web/app/assets/javascripts/feedHelper.js b/web/app/assets/javascripts/feedHelper.js index ba50c993f..9faf87f33 100644 --- a/web/app/assets/javascripts/feedHelper.js +++ b/web/app/assets/javascripts/feedHelper.js @@ -11,6 +11,7 @@ var ui = new context.JK.UIHelper(JK.app); var recordingUtils = context.JK.RecordingUtils; var userId = null; + var bandId = null; var currentFeedPage = 0; var feedBatchSize = 10; var $screen = null; @@ -35,6 +36,10 @@ query.user = userId; } + if(bandId) { + query.band = bandId; + } + return query; } @@ -83,6 +88,10 @@ userId = _userId; } + function setBand(_bandId) { + bandId = _bandId; + } + function refresh() { clearResults(); populate(); @@ -99,9 +108,9 @@ function populate() { if (isLoading || didLoadAllFeeds) return; - + setLoading(true); - + rest.getFeeds(buildQuery()) .done(function(response) { handleFeedResponse(response); @@ -566,7 +575,6 @@ var winheight = $(scrollerID).height(); var docheight = $('#'+screenID()+'-feed-entry-list').height(); var scrollTrigger = 0.90; - //console.log("feed scroll: wintop="+wintop+" docheight="+docheight+" winheight="+winheight+" ratio="+(wintop / (docheight - winheight))); if ((wintop / (docheight - winheight)) > scrollTrigger) { populate(); } @@ -606,6 +614,7 @@ this.initialize = initialize; this.refresh = refresh; this.setUser = setUser; + this.setBand = setBand; return this; } diff --git a/web/app/assets/javascripts/globals.js b/web/app/assets/javascripts/globals.js index 85ebcc250..3642ea37a 100644 --- a/web/app/assets/javascripts/globals.js +++ b/web/app/assets/javascripts/globals.js @@ -313,4 +313,26 @@ context.JK.NAMED_MESSAGES = { MASTER_VS_PERSONAL_MIX : 'master_vs_personal_mix' } + + // Recreate ChannelGroupIDs ENUM from C++ + context.JK.ChannelGroupIds = + { + "MasterGroup": 0, + "MonitorGroup": 1, + "MasterCatGroup": 2, + "MonitorCatGroup": 3, + "AudioInputMusicGroup": 4, + "AudioInputChatGroup": 5, + "MediaTrackGroup": 6, + "StreamOutMusicGroup": 7, + "StreamOutChatGroup": 8, + "StreamOutMediaGroup": 9, + "UserMusicInputGroup": 10, + "UserChatInputGroup": 11, + "UserMediaInputGroup": 12, + "PeerAudioInputMusicGroup": 13, + "PeerMediaTrackGroup": 14, + "JamTrackGroup": 15, + "MetronomeGroup": 16 + }; })(window,jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 6adbca0cc..e155a0aba 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -56,7 +56,27 @@ }); } - function uploadMusicNotations(formData) { + function getBroadcastNotification(options) { + var userId = getId(options); + return $.ajax({ + type: "GET", + url: "/api/users/" + userId + "/broadcast_notification" + }); + } + + function quietBroadcastNotification(options) { + var userId = getId(options); + var broadcast_id = options.broadcast_id; + return $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: "/api/users/" + userId + "/broadcast_notification/" + broadcast_id + '/quiet', + data: JSON.stringify({}), + }); + } + + function uploadMusicNotations(formData) { return $.ajax({ type: "POST", processData: false, @@ -168,7 +188,7 @@ if (includePending) { includeFlag = 'true'; } - + return $.ajax({ type: "GET", dataType: "json", @@ -1267,7 +1287,7 @@ function openBackingTrack(options) { var musicSessionId = options["id"]; delete options["id"]; - + return $.ajax({ type: "POST", dataType: "json", @@ -1330,7 +1350,7 @@ function openMetronome(options) { var musicSessionId = options["id"]; delete options["id"]; - + return $.ajax({ type: "POST", dataType: "json", @@ -1339,11 +1359,11 @@ data: JSON.stringify(options) }) } - + function closeMetronome(options) { var musicSessionId = options["id"]; delete options["id"]; - + return $.ajax({ type: "POST", dataType: "json", @@ -1352,7 +1372,7 @@ data: JSON.stringify(options) }) } - + function discardRecording(options) { var recordingId = options["id"]; @@ -1591,7 +1611,7 @@ url: '/api/recurly/payment_history', dataType: "json", contentType: 'application/json' - }); + }); } function getSalesHistory(options) { @@ -1687,7 +1707,7 @@ function placeOrder() { return $.ajax({ - type: "POST", + type: "POST", url: '/api/recurly/place_order', dataType: "json", contentType: 'application/json' @@ -1820,6 +1840,8 @@ this.createScheduledSession = createScheduledSession; this.uploadMusicNotations = uploadMusicNotations; this.getMusicNotation = getMusicNotation; + this.getBroadcastNotification = getBroadcastNotification; + this.quietBroadcastNotification = quietBroadcastNotification; this.legacyJoinSession = legacyJoinSession; this.joinSession = joinSession; this.cancelSession = cancelSession; @@ -1908,7 +1930,7 @@ this.openJamTrack = openJamTrack this.openBackingTrack = openBackingTrack this.closeBackingTrack = closeBackingTrack - this.closeMetronome = closeMetronome; + this.closeMetronome = closeMetronome; this.closeJamTrack = closeJamTrack; this.openMetronome = openMetronome; this.closeMetronome = closeMetronome; @@ -1975,9 +1997,6 @@ this.createAlert = createAlert; this.signup = signup; this.portOverCarts = portOverCarts; - return this; }; - - })(window,jQuery); diff --git a/web/app/assets/javascripts/layout.js b/web/app/assets/javascripts/layout.js index ac49684e6..51ce008dd 100644 --- a/web/app/assets/javascripts/layout.js +++ b/web/app/assets/javascripts/layout.js @@ -202,7 +202,12 @@ var gridRows = layout.split('x')[0]; var gridCols = layout.split('x')[1]; - $grid.children().each(function () { + var gutterWidth = 0; + + var findCardLayout; + var feedCardLayout; + + $grid.find('.homecard').each(function () { var childPosition = $(this).attr("layout-grid-position"); var childRow = childPosition.split(',')[1]; var childCol = childPosition.split(',')[0]; @@ -211,6 +216,13 @@ var childLayout = me.getCardLayout(gridWidth, gridHeight, gridRows, gridCols, childRow, childCol, childRowspan, childColspan); + if($(this).is('.feed')) { + feedCardLayout = childLayout; + } + else if($(this).is('.findsession')) { + findCardLayout = childLayout; + } + $(this).animate({ width: childLayout.width, height: childLayout.height, @@ -218,6 +230,18 @@ left: childLayout.left }, opts.animationDuration); }); + + var broadcastWidth = findCardLayout.width + feedCardLayout.width; + + layoutBroadcast(broadcastWidth, findCardLayout.left); + } + + function layoutBroadcast(width, left) { + var css = { + width:width + opts.gridPadding * 2, + left:left + } + $('[data-react-class="BroadcastHolder"]').animate(css, opts.animationDuration) } function layoutSidebar(screenWidth, screenHeight) { diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js index 1c6582771..fe616b7d7 100644 --- a/web/app/assets/javascripts/profile.js +++ b/web/app/assets/javascripts/profile.js @@ -30,21 +30,21 @@ var $studioCount = $screen.find('#studio-count'); // performance samples - var $noSamples = $screen.find('#no-samples'); - var $jamkazamSamples = $screen.find('#jamkazam-samples'); - var $soundCloudSamples = $screen.find('#soundcloud-samples'); - var $youTubeSamples = $screen.find('#youtube-samples'); + var $noSamples = $screen.find('.no-samples'); + var $jamkazamSamples = $screen.find('.jamkazam-samples'); + var $soundCloudSamples = $screen.find('.soundcloud-samples'); + var $youTubeSamples = $screen.find('.youtube-samples'); // online presence - var $noOnlinePresence = $screen.find('#no-online-presence'); - var $userWebsite = $screen.find('#user-website'); - var $soundCloudPresence = $screen.find('#soundcloud-presence'); - var $reverbNationPresence = $screen.find('#reverbnation-presence'); - var $bandCampPresence = $screen.find('#bandcamp-presence'); - var $fandalismPresence = $screen.find('#fandalism-presence'); - var $youTubePresence = $screen.find('#youtube-presence'); - var $facebookPresence = $screen.find('#facebook-presence'); - var $twitterPresence = $screen.find('#twitter-presence'); + var $noOnlinePresence = $screen.find('.no-online-presence'); + var $userWebsite = $screen.find('.user-website'); + var $soundCloudPresence = $screen.find('.soundcloud-presence'); + var $reverbNationPresence = $screen.find('.reverbnation-presence'); + var $bandCampPresence = $screen.find('.bandcamp-presence'); + var $fandalismPresence = $screen.find('.fandalism-presence'); + var $youTubePresence = $screen.find('.youtube-presence'); + var $facebookPresence = $screen.find('.facebook-presence'); + var $twitterPresence = $screen.find('.twitter-presence'); // current interests var $noInterests = $screen.find('#no-interests'); @@ -66,16 +66,16 @@ // tabs var $aboutLink = $screen.find('#about-link'); var $aboutContent = $screen.find('#about-content'); - + var $historyLink = $screen.find('#history-link'); var $historyContent = $screen.find('#history-content'); - + var $bandsLink = $screen.find('#bands-link'); var $bandsContent = $screen.find('#bands-content'); - + var $socialLink = $screen.find('#social-link'); var $socialContent = $screen.find('#social-content'); - + var $favoritesLink = $screen.find('#favorites-link'); var $favoritesContent = $screen.find('#favorites-content'); @@ -112,27 +112,15 @@ var instrument_logo_map = context.JK.getInstrumentIconMap24(); - var proficiencyDescriptionMap = { - "1": "BEGINNER", - "2": "INTERMEDIATE", - "3": "EXPERT" - }; - - var proficiencyCssMap = { - "1": "proficiency-beginner", - "2": "proficiency-intermediate", - "3": "proficiency-expert" - }; - function beforeShow(data) { userId = data.id; - feed.setUser(userId); + feed.setUser(userId); } function afterShow(data) { initUser(); resetForm(); - renderAllStats(); + renderAllStats(); } function beforeHide(data) { @@ -265,11 +253,11 @@ $soundCloudSamples.off("click", "a.sound-cloud-playable") .on("click", "a.sound-cloud-playable", playSoundCloudFile) } - function playSoundCloudFile(e) { + function playSoundCloudFile(e) { e.preventDefault(); var url = $(this).attr("soundcloud_url") var cap = $(this).text() - player.initialize(url, cap); + player.initialize(url, cap); app.layout.showDialog('sound-cloud-player-dialog'); return false; } @@ -432,7 +420,7 @@ $favoritesContent.hide(); $('.profile-nav a.active').removeClass('active'); - $aboutLink.addClass('active'); + $aboutLink.addClass('active'); } function renderAllStats() { @@ -497,170 +485,15 @@ } function renderMusicalExperience() { - $instruments.empty(); - - if (user.instruments) { - for (var i = 0; i < user.instruments.length; i++) { - var instrument = user.instruments[i]; - var description = instrument.instrument_id; - var proficiency = instrument.proficiency_level; - var instrument_icon_url = context.JK.getInstrumentIcon256(description); - - // add instrument info to layout - var template = $('#template-profile-instruments').html(); - var instrumentHtml = context.JK.fillTemplate(template, { - instrument_logo_url: instrument_icon_url, - instrument_description: description, - proficiency_level: proficiencyDescriptionMap[proficiency], - proficiency_level_css: proficiencyCssMap[proficiency] - }); - - $instruments.append(instrumentHtml); - } - } - - // status - var status = user.skill_level; - $musicianStatus.html(status ? profileUtils.skillLevelMap[status] + ' musician' : NOT_SPECIFIED_TEXT) - - // genres - $genres.empty(); - var profileGenres = profileUtils.profileGenreList(user.genres); - $genres.append(profileGenres.length > 0 ? profileGenres : NOT_SPECIFIED_TEXT); - - // concert gigs - var concertGigCount = user.concert_count; - $concertCount.html(concertGigCount > 0 ? 'Has played ' + profileUtils.gigMap[concertGigCount] + ' live concert gigs' : NOT_SPECIFIED_TEXT); - - // studio gigs - var studioGigCount = user.studio_session_count; - $studioCount.html(studioGigCount > 0 ? 'Has played ' + profileUtils.gigMap[studioGigCount] + ' studio session gigs' : NOT_SPECIFIED_TEXT); + profileUtils.renderMusicalExperience(user, $screen) } function renderPerformanceSamples() { - // performance samples - var performanceSamples = user.performance_samples; - if (!performanceSamples || performanceSamples.length === 0) { - $noSamples.show(); - hideElements([$jamkazamSamples, $soundCloudSamples, $youTubeSamples]); - if (isCurrentUser()) { - $btnAddRecordings.show(); - } - } else { - $btnAddRecordings.hide(); - $noSamples.hide(); - - // show samples section - var jamkazamSamples = profileUtils.jamkazamSamples(user.performance_samples); - if (!jamkazamSamples || jamkazamSamples.length === 0) { - hideElements([$jamkazamSamples]); - } - - var soundCloudSamples = profileUtils.soundCloudSamples(user.performance_samples); - if (!soundCloudSamples || soundCloudSamples.length === 0) { - hideElements([$soundCloudSamples]); - } - - var youTubeSamples = profileUtils.youTubeSamples(user.performance_samples); - if (!youTubeSamples || youTubeSamples.length === 0) { - hideElements([$youTubeSamples]); - } - - $.each(jamkazamSamples, function(index, sample) { - $jamkazamSamples.append("" + formatTitle(sample.claimed_recording.name) + "
"); - }); - - $.each(soundCloudSamples, function(index, sample) { - $soundCloudSamples.append("" + formatTitle(sample.description) + "
"); - }); - - $.each(youTubeSamples, function(index, sample) { - $youTubeSamples.append("" + formatTitle(sample.description) + "
"); - }); - } - } - - function formatTitle(title) { - return title && title.length > 30 ? title.substring(0, 30) + "..." : title; + profileUtils.renderPerformanceSamples(user, $screen) } function renderOnlinePresence() { - // online presences - var onlinePresences = user.online_presences; - if ((!onlinePresences || onlinePresences.length === 0) && !user.website) { - $noOnlinePresence.show(); - hideElements([$userWebsite, $soundCloudPresence, $reverbNationPresence, $bandCampPresence, - $fandalismPresence, $youTubePresence, $facebookPresence, $twitterPresence]); - - if (isCurrentUser()) { - $btnAddSites.show(); - } else { - $btnAddSites.hide(); - } - } else { - $btnAddSites.hide(); - $noOnlinePresence.hide(); - - if (user.website) { - $userWebsite.find('a').attr('href', user.website); - } - - var soundCloudPresences = profileUtils.soundCloudPresences(onlinePresences); - if (soundCloudPresences && soundCloudPresences.length > 0) { - $soundCloudPresence.find('a').attr('href', 'http://www.soundcloud.com/' + soundCloudPresences[0].username); - $soundCloudPresence.show(); - } else { - $soundCloudPresence.hide(); - } - - var reverbNationPresences = profileUtils.reverbNationPresences(onlinePresences); - if (reverbNationPresences && reverbNationPresences.length > 0) { - $reverbNationPresence.find('a').attr('href', 'http://www.reverbnation.com/' + reverbNationPresences[0].username); - $reverbNationPresence.show(); - } else { - $reverbNationPresence.hide(); - } - - var bandCampPresences = profileUtils.bandCampPresences(onlinePresences); - if (bandCampPresences && bandCampPresences.length > 0) { - $bandCampPresence.find('a').attr('href', 'http://' + bandCampPresences[0].username + '.bandcamp.com/'); - $bandCampPresence.show(); - } else { - $bandCampPresence.hide(); - } - - var fandalismPresences = profileUtils.fandalismPresences(onlinePresences); - if (fandalismPresences && fandalismPresences.length > 0) { - $fandalismPresence.find('a').attr('href', 'http://www.fandalism.com/' + fandalismPresences[0].username); - $fandalismPresence.show(); - } else { - $fandalismPresence.hide(); - } - - var youTubePresences = profileUtils.youTubePresences(onlinePresences); - if (youTubePresences && youTubePresences.length > 0) { - $youTubePresence.find('a').attr('href', 'http://www.youtube.com/' + youTubePresences[0].username); - $youTubePresence.show(); - } else { - $youTubePresence.hide(); - } - - var facebookPresences = profileUtils.facebookPresences(onlinePresences); - if (facebookPresences && facebookPresences.length > 0) { - $facebookPresence.find('a').attr('href', 'http://www.facebook.com/' + facebookPresences[0].username); - $facebookPresence.show(); - } else { - $facebookPresence.hide(); - } - - var twitterPresences = profileUtils.twitterPresences(onlinePresences); - if (twitterPresences && twitterPresences.length > 0) { - $twitterPresence.find('a').attr('href', 'http://www.twitter.com/' + twitterPresences[0].username); - $twitterPresence.show(); - } else { - $twitterPresence.hide(); - } - } + profileUtils.renderOnlinePresence(user, $screen) } function renderInterests() { @@ -943,11 +776,11 @@ }); $bandsContent.append(bandHtml); - - $('.profile-band-link-member-true').each(function(idx) { + + $('.profile-band-link-member-true').each(function(idx) { isBandMember ? $(this).show() : $(this).hide(); }); - $('.profile-band-link-member-false').each(function(idx) { + $('.profile-band-link-member-false').each(function(idx) { isBandMember ? $(this).hide() : $(this).show(); }); @@ -1078,7 +911,7 @@ app.bindScreen('profile', screenBindings); events(); initializeFeed(); - player = new context.JK.SoundCloudPlayerDialog(app); + player = new context.JK.SoundCloudPlayerDialog(app); } this.initialize = initialize; diff --git a/web/app/assets/javascripts/profile_utils.js b/web/app/assets/javascripts/profile_utils.js index d3c47f682..6c226b9e8 100644 --- a/web/app/assets/javascripts/profile_utils.js +++ b/web/app/assets/javascripts/profile_utils.js @@ -17,6 +17,21 @@ var FREE_SESSION_GENRE_TYPE = 'free_sessions'; var COWRITING_GENRE_TYPE = 'cowriting'; + var NOT_SPECIFIED_TEXT = 'Not specified'; + + var proficiencyDescriptionMap = { + "1": "BEGINNER", + "2": "INTERMEDIATE", + "3": "EXPERT" + }; + + var proficiencyCssMap = { + "1": "proficiency-beginner", + "2": "proficiency-intermediate", + "3": "proficiency-expert" + }; + + // performance sample types profileUtils.SAMPLE_TYPES = { JAMKAZAM: {description: "jamkazam"}, @@ -87,8 +102,8 @@ // Initialize standard profile help bubbles (topics stored as attributes on element): profileUtils.initializeHelpBubbles = function(parentElement) { $(".help", parentElement).each(function( index ) { - context.JK.helpBubble($(this), $(this).attr("help-topic"), {}, {}) - }) + context.JK.helpBubble($(this), $(this).attr("help-topic"), {}, {}) + }) } // profile genres @@ -270,4 +285,231 @@ return matches; } + // Render band instruments to a string: + profileUtils.renderBandInstruments = function (band) { + var msg = "" + if (band.instruments) { + for (var i = 0; i < band.instruments.length; i++) { + var instrument = band.instruments[i] + var description = instrument.instrument_id + + if (msg.length > 0) { + msg += ", " + } + msg += instrument + msg += "(" + proficiencyDescriptionMap[instrument.proficiency_level] + ")" + } + } + if (msg.length==0) { + msg = "None specified" + } + return msg + } + + function formatTitle(title) { + return title && title.length > 30 ? title.substring(0, 30) + "..." : title; + } + + profileUtils.renderMusicalExperience = function(player, $root) { + var $instruments = $root.find('#instruments'); + var $musicianStatus = $root.find('#musician-status'); + var $genres = $root.find('#genres'); + var $concertCount = $root.find('#concert-count'); + var $studioCount = $root.find('#studio-count'); + + $instruments.empty(); + + if (player.instruments) { + for (var i = 0; i < player.instruments.length; i++) { + var instrument = player.instruments[i]; + var description = instrument.instrument_id; + var proficiency = instrument.proficiency_level; + var instrument_icon_url = context.JK.getInstrumentIcon256(description); + + // add instrument info to layout + var template = $('#template-profile-instruments').html(); + var instrumentHtml = context.JK.fillTemplate(template, { + instrument_logo_url: instrument_icon_url, + instrument_description: description, + proficiency_level: proficiencyDescriptionMap[proficiency], + proficiency_level_css: proficiencyCssMap[proficiency] + }); + + $instruments.append(instrumentHtml); + } + } + + // status + var status = player.skill_level; + $musicianStatus.html(status ? profileUtils.skillLevelMap[status] + ' musician' : NOT_SPECIFIED_TEXT) + + // genres + $genres.empty(); + var profileGenres = profileUtils.profileGenreList(player.genres); + $genres.append(profileGenres.length > 0 ? profileGenres : NOT_SPECIFIED_TEXT); + + // concert gigs + var concertCount = player.concert_count; + $concertCount.html(concertCount > 0 ? 'Has played ' + profileUtils.gigMap[concertCount] + ' live concert gigs' : NOT_SPECIFIED_TEXT); + + // studio gigs + var studioCount = player.studio_session_count; + $studioCount.html(studioCount > 0 ? 'Has played ' + profileUtils.gigMap[studioCount] + ' studio session gigs' : NOT_SPECIFIED_TEXT); + + }// function renderMusicalExperience + + profileUtils.renderPerformanceSamples = function(player, $root, isOwner) { + // performance samples + var performanceSamples = player.performance_samples; + var $noSamples = $root.find('.no-samples'); + var $jamkazamSamples = $root.find('.jamkazam-samples'); + var $soundCloudSamples = $root.find('.soundcloud-samples'); + var $youTubeSamples = $root.find('.youtube-samples'); + var $btnAddRecordings = $root.find('.add-recordings'); + + if (!performanceSamples || performanceSamples.length === 0) { + $noSamples.show() + $jamkazamSamples.hide() + $soundCloudSamples.hide() + $youTubeSamples.hide() + if (isOwner) { + $btnAddRecordings.show(); + } + } else { + $btnAddRecordings.hide(); + $noSamples.hide(); + + // show samples section + var jamkazamSamples = profileUtils.jamkazamSamples(player.performance_samples); + if (!jamkazamSamples || jamkazamSamples.length === 0) { + $jamkazamSamples.hide() + } else { + $jamkazamSamples.show() + } + + var soundCloudSamples = profileUtils.soundCloudSamples(player.performance_samples); + if (!soundCloudSamples || soundCloudSamples.length === 0) { + $soundCloudSamples.hide() + } else { + $soundCloudSamples.show() + } + + var youTubeSamples = profileUtils.youTubeSamples(player.performance_samples); + if (!youTubeSamples || youTubeSamples.length === 0) { + $youTubeSamples.hide() + } else { + $youTubeSamples.show() + } + + $.each(jamkazamSamples, function(index, sample) { + $jamkazamSamples.append("" + formatTitle(sample.claimed_recording.name) + "
"); + }); + + $.each(soundCloudSamples, function(index, sample) { + $soundCloudSamples.append("" + formatTitle(sample.description) + "
"); + }); + + $.each(youTubeSamples, function(index, sample) { + $youTubeSamples.append("" + formatTitle(sample.description) + "
"); + }); + } + }// function renderPerformanceSamples + + profileUtils.renderOnlinePresence = function(player, $root, isOwner) { + var $noOnlinePresence = $root.find('.no-online-presence'); + var $userWebsite = $root.find('.user-website'); + var $soundCloudPresence = $root.find('.soundcloud-presence'); + var $reverbNationPresence = $root.find('.reverbnation-presence'); + var $bandCampPresence = $root.find('.bandcamp-presence'); + var $fandalismPresence = $root.find('.fandalism-presence'); + var $youTubePresence = $root.find('.youtube-presence'); + var $facebookPresence = $root.find('.facebook-presence'); + var $twitterPresence = $root.find('.twitter-presence'); + var $btnAddSites = $root.find('.add-sites'); + + + + // online presences + var onlinePresences = player.online_presences; + if ((!onlinePresences || onlinePresences.length === 0) && !player.website) { + $noOnlinePresence.show() + $userWebsite.show() + $soundCloudPresence.show() + $reverbNationPresence.show() + $bandCampPresence.show() + $fandalismPresence.show() + $youTubePresence.show() + $facebookPresence.show() + $twitterPresence.show() + + if (isOwner) { + $btnAddSites.show(); + } else { + $btnAddSites.hide(); + } + } else { + $btnAddSites.hide(); + $noOnlinePresence.hide(); + + if (player.website) { + $userWebsite.find('a').attr('href', player.website); + } + + var soundCloudPresences = profileUtils.soundCloudPresences(onlinePresences); + if (soundCloudPresences && soundCloudPresences.length > 0) { + $soundCloudPresence.find('a').attr('href', 'http://www.soundcloud.com/' + soundCloudPresences[0].username); + $soundCloudPresence.show(); + } else { + $soundCloudPresence.hide(); + } + + var reverbNationPresences = profileUtils.reverbNationPresences(onlinePresences); + if (reverbNationPresences && reverbNationPresences.length > 0) { + $reverbNationPresence.find('a').attr('href', 'http://www.reverbnation.com/' + reverbNationPresences[0].username); + $reverbNationPresence.show(); + } else { + $reverbNationPresence.hide(); + } + + var bandCampPresences = profileUtils.bandCampPresences(onlinePresences); + if (bandCampPresences && bandCampPresences.length > 0) { + $bandCampPresence.find('a').attr('href', 'http://' + bandCampPresences[0].username + '.bandcamp.com/'); + $bandCampPresence.show(); + } else { + $bandCampPresence.hide(); + } + + var fandalismPresences = profileUtils.fandalismPresences(onlinePresences); + if (fandalismPresences && fandalismPresences.length > 0) { + $fandalismPresence.find('a').attr('href', 'http://www.fandalism.com/' + fandalismPresences[0].username); + $fandalismPresence.show(); + } else { + $fandalismPresence.hide(); + } + + var youTubePresences = profileUtils.youTubePresences(onlinePresences); + if (youTubePresences && youTubePresences.length > 0) { + $youTubePresence.find('a').attr('href', 'http://www.youtube.com/' + youTubePresences[0].username); + $youTubePresence.show(); + } else { + $youTubePresence.hide(); + } + + var facebookPresences = profileUtils.facebookPresences(onlinePresences); + if (facebookPresences && facebookPresences.length > 0) { + $facebookPresence.find('a').attr('href', 'http://www.facebook.com/' + facebookPresences[0].username); + $facebookPresence.show(); + } else { + $facebookPresence.hide(); + } + + var twitterPresences = profileUtils.twitterPresences(onlinePresences); + if (twitterPresences && twitterPresences.length > 0) { + $twitterPresence.find('a').attr('href', 'http://www.twitter.com/' + twitterPresences[0].username); + $twitterPresence.show(); + } else { + $twitterPresence.hide(); + } + } + }// function renderOnlinePresence })(window, jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components.js b/web/app/assets/javascripts/react-components.js new file mode 100644 index 000000000..c16b9faa7 --- /dev/null +++ b/web/app/assets/javascripts/react-components.js @@ -0,0 +1,3 @@ +//= require ./react-components/actions/BroadcastActions +//= require ./react-components/stores/BroadcastStore +//= require_directory ./react-components \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/.gitkeep b/web/app/assets/javascripts/react-components/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/web/app/assets/javascripts/react-components/Broadcast.js.jsx.coffee b/web/app/assets/javascripts/react-components/Broadcast.js.jsx.coffee new file mode 100644 index 000000000..59b5b147f --- /dev/null +++ b/web/app/assets/javascripts/react-components/Broadcast.js.jsx.coffee @@ -0,0 +1,45 @@ +context = window + +broadcastActions = window.JK.Actions.Broadcast; +rest = window.JK.Rest(); + +Broadcast = React.createClass({ + displayName: 'Broadcast Notification' + + handleNavigate: (e) -> + href = $(e.currentTarget).attr('href') + + if href.indexOf('http') == 0 + e.preventDefault() + window.JK.popExternalLink(href) + + broadcastActions.hide.trigger() + + + notNow: (e) -> + e.preventDefault(); + rest.quietBroadcastNotification({broadcast_id: this.props.notification.id}) + broadcastActions.hide.trigger() + + + createMarkup: () -> + {__html: this.props.notification.message}; + + + render: () -> + `
+
+
+
+ {this.props.notification.button_label} +
+ not now, thanks + +
+
+
` + }) + +context.JK.Components.Broadcast = Broadcast +context.Broadcast = Broadcast \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/BroadcastHolder.js.jsx.coffee b/web/app/assets/javascripts/react-components/BroadcastHolder.js.jsx.coffee new file mode 100644 index 000000000..10b4ac023 --- /dev/null +++ b/web/app/assets/javascripts/react-components/BroadcastHolder.js.jsx.coffee @@ -0,0 +1,27 @@ +context = window + +ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; + +BroadcastHolder = React.createClass( + { + displayName: 'Broadcast Notification Holder', + + mixins: [Reflux.connect(context.JK.Stores.Broadcast, 'notification')] + + render: -> + notification = [] + if this.state.notification + notification.push(``) + + + `
+ + {notification} + +
` + + + }); + +context.JK.Components.BroadcastHolder = BroadcastHolder +context.BroadcastHolder = BroadcastHolder diff --git a/web/app/assets/javascripts/react-components/actions/BroadcastActions.js.coffee b/web/app/assets/javascripts/react-components/actions/BroadcastActions.js.coffee new file mode 100644 index 000000000..7761257d2 --- /dev/null +++ b/web/app/assets/javascripts/react-components/actions/BroadcastActions.js.coffee @@ -0,0 +1,8 @@ +context = window + +BroadcastActions = Reflux.createActions({ + load: {asyncResult: true}, + hide: {} +}) + +context.JK.Actions.Broadcast = BroadcastActions diff --git a/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee b/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee new file mode 100644 index 000000000..e6b9b297b --- /dev/null +++ b/web/app/assets/javascripts/react-components/stores/BroadcastStore.js.coffee @@ -0,0 +1,31 @@ +$ = jQuery +context = window +logger = context.JK.logger +broadcastActions = context.JK.Actions.Broadcast + +rest = context.JK.Rest() + +broadcastActions.load.listenAndPromise(rest.getBroadcastNotification); + +BroadcastStore = Reflux.createStore( + { + listenables: broadcastActions + + onLoad: () -> + logger.debug("loading broadcast notification...") + + onLoadCompleted: (response) -> + logger.debug("broadcast notification sync completed") + this.trigger(response) + + onLoadFailed: (jqXHR) -> + if jqXHR.status != 404 + logger.error("broadcast notification sync failed") + + onHide: () -> + this.trigger(null) + } +) + +context.JK.Stores.Broadcast = BroadcastStore + diff --git a/web/app/assets/javascripts/react-init.js b/web/app/assets/javascripts/react-init.js new file mode 100644 index 000000000..e6571c691 --- /dev/null +++ b/web/app/assets/javascripts/react-init.js @@ -0,0 +1,3 @@ +window.JK.Actions = {} +window.JK.Stores = {} +window.JK.Components = {} \ No newline at end of file diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index a00991840..1827758af 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -14,6 +14,7 @@ var logger = context.JK.logger; var self = this; var webcamViewer = new context.JK.WebcamViewer() + var ChannelGroupIds = context.JK.ChannelGroupIds; var defaultParticipant = { tracks: [{ @@ -39,23 +40,6 @@ height: 83 }; - // Recreate ChannelGroupIDs ENUM from C++ - var ChannelGroupIds = { - "MasterGroup": 0, - "MonitorGroup": 1, - "AudioInputMusicGroup": 2, - "AudioInputChatGroup": 3, - "MediaTrackGroup": 4, - "StreamOutMusicGroup": 5, - "StreamOutChatGroup": 6, - "UserMusicInputGroup": 7, - "UserChatInputGroup": 8, - "PeerAudioInputMusicGroup": 9, - "PeerMediaTrackGroup": 10, - "JamTrackGroup": 11, - "MetronomeGroup": 12 - }; - var METRO_SOUND_LOOKUP = { 0 : "BuiltIn", 1 : "SineWave", diff --git a/web/app/assets/javascripts/site_validator.js.coffee b/web/app/assets/javascripts/site_validator.js.coffee index 41636af26..111457aff 100644 --- a/web/app/assets/javascripts/site_validator.js.coffee +++ b/web/app/assets/javascripts/site_validator.js.coffee @@ -9,8 +9,8 @@ context.JK.SiteValidator = class SiteValidator @rest = context.JK.Rest() @site_type = site_type @input_div = $(".site_validator."+site_type+"_validator", parent) - @data_input = @input_div.find('input') - + @data_input = @input_div.find('input') + @logger = context.JK.logger @spinner = @input_div.find('span.spinner-small') @checkmark = @input_div.find('.validate-checkmark') @@ -34,7 +34,7 @@ context.JK.SiteValidator = class SiteValidator @site_status = null dataToValidate: () => - url = @data_input.val() + url = @data_input.val() if url && 0 < url.length url.substring(0,2000) else @@ -50,7 +50,7 @@ context.JK.SiteValidator = class SiteValidator @checkmark.hide() yn - didBlur: () => + didBlur: () => if this.showFormatStatus() this.validateSite() @@ -100,14 +100,14 @@ context.JK.SiteValidator = class SiteValidator @checkmark.show() else @checkmark.hide() - - siteIsValid: () => + + siteIsValid: () => this.setSiteStatus(true) - - siteIsInvalid: () => + + siteIsInvalid: () => this.setSiteStatus(false) - - renderErrors: (errors) => + + renderErrors: (errors) => errdiv = @input_div.find('.error') if errmsg = context.JK.format_errors("site", errors) errdiv.show() @@ -120,7 +120,7 @@ context.JK.SiteValidator = class SiteValidator dfr = $.Deferred() if null == @site_status @deferred_status_check = dfr - this.validateSite() + this.validateSite() else if true == @site_status dfr.resolve() @@ -128,9 +128,9 @@ context.JK.SiteValidator = class SiteValidator dfr.reject() return dfr.promise() - -context.JK.RecordingSourceValidator = class RecordingSourceValidator extends SiteValidator - constructor: (site_type, success_callback, fail_callback, parent) -> + +context.JK.RecordingSourceValidator = class RecordingSourceValidator extends SiteValidator + constructor: (site_type, success_callback, fail_callback, parent) -> super(site_type, success_callback, fail_callback, parent) @recording_sources = [] @is_rec_src = true @@ -142,7 +142,7 @@ context.JK.RecordingSourceValidator = class RecordingSourceValidator extends Sit super() if sources @recording_sources = sources - @add_btn.on 'click', => + @add_btn.off('click').on 'click', => this.attemptAdd() processSiteCheckSucceed: (response) => @@ -163,7 +163,7 @@ context.JK.RecordingSourceValidator = class RecordingSourceValidator extends Sit if @site_fail_callback @site_fail_callback(@input_div) - didBlur: () => + didBlur: () => # do nothing, validate on add only validateSite: () => @@ -177,13 +177,14 @@ context.JK.RecordingSourceValidator = class RecordingSourceValidator extends Sit removeRecordingId: (recording_id) => start_len = @recording_sources.length - @recording_sources = $.grep @recording_sources, (src_data) -> - src_data['recording_id'] != recording_id + @recording_sources = @recording_sources.filter (src) -> + src["recording_id"] isnt recording_id.toString() start_len != @recording_sources.length containsRecordingUrl: (url) => vals = $.grep @recording_sources, (src_data) -> - src_data['url'] == url + src_data['url'] is url + 0 < vals.length recordingSources: () => diff --git a/web/app/assets/javascripts/trackHelpers.js b/web/app/assets/javascripts/trackHelpers.js index b434d80a9..b6c61385e 100644 --- a/web/app/assets/javascripts/trackHelpers.js +++ b/web/app/assets/javascripts/trackHelpers.js @@ -20,7 +20,7 @@ var userTracks = context.JK.TrackHelpers.getUserTracks(jamClient, allTracks); var backingTracks = context.JK.TrackHelpers.getBackingTracks(jamClient, allTracks); - var metronomeTracks = context.JK.TrackHelpers.getTracks(jamClient, 12); + var metronomeTracks = context.JK.TrackHelpers.getTracks(jamClient, 16); return { userTracks: userTracks, @@ -51,7 +51,7 @@ // allTracks is the result of SessionGetAllControlState; as an optimization getBackingTracks: function(jamClient, allTracks) { - var mediaTracks = context.JK.TrackHelpers.getTracks(jamClient, 4, allTracks); + var mediaTracks = context.JK.TrackHelpers.getTracks(jamClient, 6, allTracks); var backingTracks = [] context._.each(mediaTracks, function(mediaTrack) { @@ -80,7 +80,7 @@ var localMusicTracks = []; var i; - localMusicTracks = context.JK.TrackHelpers.getTracks(jamClient, 2, allTracks); + localMusicTracks = context.JK.TrackHelpers.getTracks(jamClient, 4, allTracks); var trackObjects = []; diff --git a/web/app/assets/stylesheets/client/accountProfileSamples.css.scss b/web/app/assets/stylesheets/client/accountProfileSamples.css.scss index a6f641d57..76c76ebc8 100644 --- a/web/app/assets/stylesheets/client/accountProfileSamples.css.scss +++ b/web/app/assets/stylesheets/client/accountProfileSamples.css.scss @@ -1,11 +1,11 @@ @import "common.css.scss"; @import "site_validator.css.scss"; -.profile-online-sample-controls { +.profile-online-sample-controls { table.profile-table { width: 100%; tr:nth-child(even) td { - padding: 0.25em 0.25em 1em 0.25em; + padding: 0.25em 0.25em 1em 0.25em; vertical-align: top; } tr:nth-child(odd) td { @@ -14,10 +14,23 @@ } } + .sample-list { + border: 1px inset #cfcfcf; + padding: 0.5em; + .empty { + font-style: italic; + } + min-height: 150px; + overflow: scroll; + .close-button { + cursor:pointer; + } + } + table.control-table { width: 100%; } - + .sample-row { position: relative; clear: both; @@ -29,12 +42,12 @@ } .presence { - margin: 3px 30px 15px 0px; + margin: 3px 30px 15px 0px; } .site_validator { a, .spinner-small { - margin: 1px 1px 2px 2px; + margin: 1px 1px 2px 2px; vertical-align: top; } } diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index 59c8c330f..b9cbb655b 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -15,6 +15,16 @@ } } + + + table.summary-table { + tr { + td { + padding-right: 1em; + } + } + } + // Mimic style of easydropdown selects: input[type="number"] { border-radius: 6px; @@ -43,18 +53,7 @@ } } - tr:nth-child(even) td { - padding-bottom: 1em; - } - - td.band-biography, td.tdBandGenres { - height:100%; - vertical-align: top; - #band-biography { - - } - } - + .band-setup-genres { width:100%; @@ -190,6 +189,20 @@ border-radius:44px; } + + .band-entry { + .item-caption { + font-size: 1.4em; + font-weight: bold; + margin: 0.25em 0em 0.25em 0em; + } + .item-content { + font-size: 1.1em; + margin: 0.25em 0em 0.25em 0em; + } + margin: 0em 0em 1.5em 0em; + } + // .band-name, .band-photo { // display: inline; // } @@ -392,6 +405,19 @@ table.band-form-table { width: 100%; margin: 1em; + + tr:nth-child(even) td { + padding-bottom: 1em; + } + + td.band-biography, td.tdBandGenres { + height:100%; + vertical-align: top; + #band-biography { + + } + } + } .easydropdown { diff --git a/web/app/assets/stylesheets/client/client.css b/web/app/assets/stylesheets/client/client.css index 0e0bee1f1..c26547f68 100644 --- a/web/app/assets/stylesheets/client/client.css +++ b/web/app/assets/stylesheets/client/client.css @@ -84,4 +84,5 @@ *= require ./jamTrackPreview *= require users/signinCommon *= require landings/partner_agreement_v1 + *= require_directory ./react-components */ \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/profile.css.scss b/web/app/assets/stylesheets/client/profile.css.scss index 5328a80c2..6e5665b5e 100644 --- a/web/app/assets/stylesheets/client/profile.css.scss +++ b/web/app/assets/stylesheets/client/profile.css.scss @@ -12,7 +12,10 @@ div.logo, div.item { text-align: bottom; - margin-left: 1em; + } + + .online-presence-option, .performance-sample-option { + margin-right: 1em; } img.logo { @@ -35,11 +38,11 @@ } .profile-body { - + } .profile-header { padding:10px 20px; - position: relative; + position: relative; } .profile-header h2 { @@ -49,11 +52,20 @@ margin: 0px 0px 0px 0px; } -.profile-about-right .section-header { - font-weight:600; - font-size:18px; - float:left; - margin: 0px 0px 10px 0px; +.profile-about-right { + .section-header { + font-weight:600; + font-size:18px; + float:left; + margin: 0px 0px 10px 0px; + } + + .section-content { + font-weight:normal; + font-size:1.2em; + float:left; + margin: 0px 0px 10px 0px; + } } .profile-details { @@ -241,7 +253,7 @@ -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing:border-box; - + .result-name { font-size: 12px; font-weight: bold; @@ -267,11 +279,11 @@ height:24px; width:24px; margin-right:2px; - + &:last-child { margin-right:0px; } - + } } .button-row { @@ -343,14 +355,14 @@ display:none; } -#history-content { +#history-content, #band-profile-history { padding:0 10px 0 20px; width:100%; position:relative; height:100%; @include border_box_sizing; - #user-feed-controls { + #user-feed-controls, #band-feed-controls { width:100%; @include border_box_sizing; position:relative; diff --git a/web/app/assets/stylesheets/client/react-components/broadcast.css.scss b/web/app/assets/stylesheets/client/react-components/broadcast.css.scss new file mode 100644 index 000000000..25d43ad5f --- /dev/null +++ b/web/app/assets/stylesheets/client/react-components/broadcast.css.scss @@ -0,0 +1,79 @@ +@import 'client/common'; + +[data-react-class="BroadcastHolder"] { + position:absolute; + min-height:60px; + top:62px; + @include border_box_sizing; + + .broadcast-notification { + position:absolute; + border-width:1px; + border-color:$ColorScreenPrimary; + border-style:solid; + padding:5px 12px; + height:100%; + width:100%; + left:0; + top:0; + overflow:hidden; + margin-left:60px; + @include border_box_sizing; + + } + .message { + float:left; + width:calc(100% - 150px); + font-size:12px; + } + + .actions { + float:right; + text-align: right; + vertical-align: middle; + display:inline; + height:100%; + width:150px; + } + + .actionsAligner { + display:inline-block; + vertical-align:middle; + text-align:center; + } + + a { display:inline-block; } + + .button-orange { + font-size:16px; + position:relative; + top:8px; + } + + .not-now { + font-size:11px; + top:13px; + position:relative; + } +} + + +.bn-slidedown-enter { + max-height:0; + opacity: 0.01; + transition: max-height .5s ease-in; +} + +.bn-slidedown-enter.bn-slidedown-enter-active { + max-height:60px; + opacity: 1; +} + +.bn-slidedown-leave { + max-height:60px; + transition: max-height .5s ease-in; +} + +.bn-slidedown-leave.bn-slidedown-leave-active { + max-height:0; +} \ No newline at end of file diff --git a/web/app/controllers/api_users_controller.rb b/web/app/controllers/api_users_controller.rb index e8b42df82..ebe68290a 100644 --- a/web/app/controllers/api_users_controller.rb +++ b/web/app/controllers/api_users_controller.rb @@ -13,7 +13,7 @@ class ApiUsersController < ApiController :band_invitation_index, :band_invitation_show, :band_invitation_update, # band invitations :set_password, :begin_update_email, :update_avatar, :delete_avatar, :generate_filepicker_policy, :share_session, :share_recording, - :affiliate_report, :audio_latency] + :affiliate_report, :audio_latency, :broadcast_notification] respond_to :json @@ -856,6 +856,30 @@ class ApiUsersController < ApiController end end + def broadcast_notification + @broadcast = BroadcastNotification.next_broadcast(current_user) + + if @broadcast + # mark it as viewed + @broadcast.did_view(current_user) + respond_with_model(@broadcast) + else + render json: { message: 'Not Found'}, status: 404 + end + end + + # used to hide a broadcast notification from rotation temporarily + def quiet_broadcast_notification + @broadcast = BroadcastNotificationView.find_by_broadcast_notification_id_and_user_id(params[:broadcast_id], current_user.id) + + if @broadcast + @broadcast.active_at = Date.today + 14 # 14 days in the future we'll re-instas + @broadcast.save + end + + render json: { }, status: 200 + end + ###################### RECORDINGS ####################### # def recording_index # @recordings = User.recording_index(current_user, params[:id]) diff --git a/web/app/views/api_bands/show.rabl b/web/app/views/api_bands/show.rabl index dde9f8760..7c855b180 100644 --- a/web/app/views/api_bands/show.rabl +++ b/web/app/views/api_bands/show.rabl @@ -27,6 +27,18 @@ child :genres => :genres do #partial('api_genres/index', :object => @band.genres) end +child :performance_samples => :performance_samples do + attributes :id, :url, :service_type, :claimed_recording_id, :service_id, :description + + child :claimed_recording => :claimed_recording do + attributes :id, :name + end +end + +child :online_presences => :online_presences do + attributes :id, :service_type, :username +end + if current_user node :is_following do |uu| current_user.following?(@band) diff --git a/web/app/views/api_users/broadcast_notification.rabl b/web/app/views/api_users/broadcast_notification.rabl new file mode 100644 index 000000000..21a9c3f0d --- /dev/null +++ b/web/app/views/api_users/broadcast_notification.rabl @@ -0,0 +1,3 @@ +object @broadcast + +attributes :id, :message, :button_label, :button_url \ No newline at end of file diff --git a/web/app/views/clients/_account.html.erb b/web/app/views/clients/_account.html.erb index 29d806a94..2aa45e28f 100644 --- a/web/app/views/clients/_account.html.erb +++ b/web/app/views/clients/_account.html.erb @@ -105,19 +105,19 @@
- UPDATE +


-

jamtracks:

+

jamtracks:

- {{data.licenseDetail}} + {{data.licenseDetail}}
JamTracks License diff --git a/web/app/views/clients/_account_profile.html.erb b/web/app/views/clients/_account_profile.html.erb index a0f3cde6f..7d7f08256 100644 --- a/web/app/views/clients/_account_profile.html.erb +++ b/web/app/views/clients/_account_profile.html.erb @@ -85,7 +85,7 @@
- CANCEL  SAVE & NEXT +   
diff --git a/web/app/views/clients/_account_profile_experience.html.erb b/web/app/views/clients/_account_profile_experience.html.erb index 5360c22b9..6485b118f 100644 --- a/web/app/views/clients/_account_profile_experience.html.erb +++ b/web/app/views/clients/_account_profile_experience.html.erb @@ -66,9 +66,9 @@

- CANCEL   - BACK   - SAVE & NEXT +    +    +
diff --git a/web/app/views/clients/_account_profile_interests.html.erb b/web/app/views/clients/_account_profile_interests.html.erb index d5b0aaf0f..82aca53b9 100644 --- a/web/app/views/clients/_account_profile_interests.html.erb +++ b/web/app/views/clients/_account_profile_interests.html.erb @@ -207,9 +207,9 @@

- CANCEL   - BACK   - SAVE & NEXT +    +    +
diff --git a/web/app/views/clients/_account_profile_samples.html.erb b/web/app/views/clients/_account_profile_samples.html.erb index df5392e0f..22825b9f2 100644 --- a/web/app/views/clients/_account_profile_samples.html.erb +++ b/web/app/views/clients/_account_profile_samples.html.erb @@ -13,15 +13,15 @@

edit profile: online presence & performance samples

- <%= render "profile_online_sample_controls" %> + <%= render "profile_edit_presence_controls" %>


diff --git a/web/app/views/clients/_bandProfile.html.erb b/web/app/views/clients/_bandProfile.html.erb index 1a51223bd..8b0f819ce 100644 --- a/web/app/views/clients/_bandProfile.html.erb +++ b/web/app/views/clients/_bandProfile.html.erb @@ -14,12 +14,17 @@

+


@@ -43,7 +48,7 @@
-
+

Location:





Stats:


@@ -51,26 +56,105 @@

-
-
- EDIT - INVITE - DELETE + + +
+
+
Bio
+
+
+ Edit Bio +
-

-

-
-


+ +
+
+
Musical Experience
+
+ + + + + + + + + + + + + + + + + +
Genres:Genres
Concert Gigs:
Status:
Type:
+
+
-
+ +
+
+
Performance Samples
+
+ <%=render "profile_summary_performance_samples" %> +
+
+
+ +
+
+
Online Presence
+
+ <%=render "profile_summary_online_presence" %> +
+
+
+ + +
+
+
Current Interests
+
    + + + +
+
+
+
-
-
-
-
+ +
+
+ <%= form_tag('', {:id => 'band-feed-form', :class => 'inner-content'}) do %> + <%= render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_FEED, :id => 'band-feed-controls'}) %> +
+
+
+
+
No more feed entries
+
Loading ...
+
+
+
+ <% end %> +
+

diff --git a/web/app/views/clients/_band_setup.html.slim b/web/app/views/clients/_band_setup.html.slim index 5fe8d6660..05682a802 100644 --- a/web/app/views/clients/_band_setup.html.slim +++ b/web/app/views/clients/_band_setup.html.slim @@ -7,14 +7,14 @@ = render "screen_navigation" .content-body .content-body-scroller - form#band-setup-form + form#band-setup-form #band-setup-step-0.band-step.content-wrapper h2 set up band: basics table.band-form-table tr td colspan="2" - - tr#name_row + + tr#name_row td colspan="2" .band-photo.hidden span.field @@ -23,29 +23,25 @@ span.field a#band-change-photo.small.ml20 href="#" | Upload band photo. - + .band-name .field.band-field label for="band-name" | Band Name: - input#band-name type="text" maxlength="1024" value="" - / td#tdBandWebsite[] - / .field - / label for="band-website" - / | Web Site: - / input#band-website[type="text" maxlength="4000" value=""] + input#band-name type="text" maxlength="1024" value="" + tr td.band-country .field.band-field label for="band-country" | Country: select#band-country - td.band-biography rowspan="3" + td.band-biography rowspan="3" .field.band-field label for="band-biography" | Description / Bio: textarea#band-biography rows="8" - tr + tr td.band-region .field.band-field label for="band-region" @@ -58,8 +54,8 @@ | City: select#band-city - - #band-setup-step-1.band-step.content-wrapper + + #band-setup-step-1.band-step.content-wrapper h2 set up band: musical experience table.band-form-table @@ -73,7 +69,7 @@ td .field label for="band-type" Type - select#band-type.easydropdown name="band_type" + select#band-type.easydropdown name="band_type" option value="" Not Specified option value="virtual" Virtual option value="physical" Physical @@ -82,7 +78,7 @@ td .field label for="band-status" Status - select#band-status.easydropdown name="band_status" + select#band-status.easydropdown name="band_status" option value="" Not Specified option value="amateur" Amateur option value="professional" Professional @@ -91,66 +87,66 @@ td .field label for="concert-count" Concert Gigs Played - select#concert-count.easydropdown name="concert_count" + select#concert-count.easydropdown name="concert_count" option value="" Not Specified option value="0" Zero option value="1" Under 10 option value="2" 10 to 50 option value="3" 50 to 100 - option value="4" Over 100 - - #band-setup-step-2.band-step.content-wrapper + option value="4" Over 100 + + #band-setup-step-2.band-step.content-wrapper h2 set up band: current interests table.band-form-table tr td - label.strong-label for="new-member" + label.strong-label for="new-member" | We want to add a new member   - a.help help-topic="band-profile-add-new-member" [?] - td.new-member-dependent - label for="desired-experience" + a.help help-topic="band-profile-add-new-member" [?] + td.new-member-dependent + label for="desired-experience" | Desired Experience   a#choose-desired-experience select - td.new-member-dependent + td.new-member-dependent label for="play-commitment" Play Commitment td.new-member-dependent label for="touring-option" Touring Option tr td - .radio-field - input#new-member-yes.iradio-inline.dependent-master type="radio" name="add_new_members" value='yes' + .radio-field + input#new-member-yes.iradio-inline.dependent-master type="radio" name="add_new_members" value='yes' label for='new-member-yes' Yes - .radio-field - input#new-member-no.iradio-inline.dependent-master type="radio" name="add_new_members" value='no' - label for='new-member-no' No - td.new-member-dependent - #desired-experience-label None specified - td.new-member-dependent - select#play-commitment.easydropdown name="play_commitment" + .radio-field + input#new-member-no.iradio-inline.dependent-master type="radio" name="add_new_members" value='no' + label for='new-member-no' No + td.new-member-dependent + #desired-experience-label None specified + td.new-member-dependent + select#play-commitment.easydropdown name="play_commitment" option value="1" Infrequent option value="2" Once a Week option value="3" 2-3 Times Per Week - option value="4" 4+ Times Per Week + option value="4" 4+ Times Per Week td.new-member-dependent - select#touring-option.easydropdown name="touring_option" + select#touring-option.easydropdown name="touring_option" option value="yes" Yes option value="no" No tr td - label.strong-label for="paid-gigs" + label.strong-label for="paid-gigs" | We want to play paid gigs   - a.help help-topic="band-profile-play-paid-gigs" [?] + a.help help-topic="band-profile-play-paid-gigs" [?] td.paid-gigs-dependent label for="hourly-rate" Hourly Rate: td.paid-gigs-dependent label for="gig-minimum" Gig Minimum: tr td - .radio-field - input#paid-gigs-yes.iradio-inline.dependent-master type="radio" name="paid_gigs" value='yes' + .radio-field + input#paid-gigs-yes.iradio-inline.dependent-master type="radio" name="paid_gigs" value='yes' label for="paid-gigs-yes" Yes - .radio-field - input#paid-gigs-no.iradio-inline.dependent-master type="radio" name="paid_gigs" value='no' + .radio-field + input#paid-gigs-no.iradio-inline.dependent-master type="radio" name="paid_gigs" value='no' label for="paid-gigs-no" No td.paid-gigs-dependent input#hourly-rate type="number" name="hourly_rate" @@ -158,24 +154,24 @@ input#gig-minimum type="number" name="gig_minimum" tr td - label.strong-label for="free-gigs" + label.strong-label for="free-gigs" | We want to play free gigs   - a.help help-topic="band-profile-play-free-gigs" [?] + a.help help-topic="band-profile-play-free-gigs" [?] tr td - .radio-field - input#free-gigs-yes.iradio-inline type="radio" name="free_gigs" value='yes' + .radio-field + input#free-gigs-yes.iradio-inline type="radio" name="free_gigs" value='yes' label for="free-gigs-yes" Yes - .radio-field - input#free-gigs-no.iradio-inline type="radio" name="free_gigs" value='no' - label for="free-gigs-no" No + .radio-field + input#free-gigs-no.iradio-inline type="radio" name="free_gigs" value='no' + label for="free-gigs-no" No - #band-setup-step-3.band-step.content-wrapper + #band-setup-step-3.band-step.content-wrapper h2 set up band: online presence & performance samples - = render "clients/profile_online_sample_controls" - - #band-setup-step-4.band-step.content-wrapper - h2 invite members + = render "clients/profile_edit_presence_controls" + + #band-setup-step-4.band-step.content-wrapper + h2 set up band: invite members br #band-setup-invite-musicians br @@ -201,19 +197,11 @@ = image_tag("content/icon_google.png", :size => "24x24", :align => "absmiddle") .right.mt5.ml5 | Google+ - / br clear="all" - / .right - / a#btn-band-setup-back.button-grey - / | BACK - / |    - / a#btn-band-setup-save.button-orange - / | CREATE BAND - / .clearall - + br clear="all" .right a#btn-band-setup-cancel.nav-button.button-grey - | CANCEL    + | CANCEL    a#btn-band-setup-back.nav-button.button-grey.hidden | BACK a#btn-band-setup-next.nav-button.button-orange @@ -230,7 +218,7 @@ script#template-band-setup-genres type="text/template" script#template-band-invitation type="text/template" - .invitation user-id="{{userId}}" + .invitation user-id="{{userId}}" | {{userName}} a img src="shared/icon_delete_sm.png" width="13" height="13" diff --git a/web/app/views/clients/_help.html.slim b/web/app/views/clients/_help.html.slim index c81528e9c..c85cce272 100644 --- a/web/app/views/clients/_help.html.slim +++ b/web/app/views/clients/_help.html.slim @@ -267,17 +267,17 @@ script type="text/template" id="template-help-profile-interests-virtual-band" | For musicians who want to join a band that plays only online on JamKazam and does not travel and meet in person at a physical space to play. script type="text/template" id="template-help-profile-interests-traditional-band" - | For musicians who want to join a more traditional band that meets in person at a physical space to play. It may also play online on JamKazam. + | For musicians who want to join a more traditional band that meets in person at a physical space to play. It may also play online on JamKazam. script type="text/template" id="template-help-profile-interests-paid-sessions" - | For professional session musicians who are qualified and interested in playing paid recording session gigs for bands, composers, and producers. + | For professional session musicians who are qualified and interested in playing paid recording session gigs for bands, composers, and producers. script type="text/template" id="template-help-profile-interests-free-sessions" - | For skilled musicians who are interested in playing free recording session gigs for bands, composers, and producers, either for fun or to build experience and resume. + | For skilled musicians who are interested in playing free recording session gigs for bands, composers, and producers, either for fun or to build experience and resume. script type="text/template" id="template-help-profile-interests-cowrite-partners" - | For composers and songwriters who want to collaborate with others in composing and creating new music. - + | For composers and songwriters who want to collaborate with others in composing and creating new music. + script type="text/template" id="template-help-band-profile-add-new-member" | For bands that want to add one or more new members and let the JamKazam community of musicians know your band is looking for new members. @@ -285,7 +285,7 @@ script type="text/template" id="template-help-band-profile-play-paid-gigs" | For professional bands that are qualified and interested in playing paid gigs at music venues and other events. script type="text/template" id="template-help-band-profile-play-free-gigs" - | For bands that are interested in playing free gigs, either for fun or to build experience. + | For bands that are interested in playing free gigs, either for fun or to build experience. script type="text/template" id="template-help-jamtrack-landing-preview" .jamtrack-landing-preview.big-help diff --git a/web/app/views/clients/_home.html.slim b/web/app/views/clients/_home.html.slim index 9247d18f0..72ea35d4d 100644 --- a/web/app/views/clients/_home.html.slim +++ b/web/app/views/clients/_home.html.slim @@ -10,7 +10,7 @@ / Grid is the count of the smallest spaces, then / individual spells span those spaces -if @nativeClient - .grid layout-grid="2x12" + .grid layout-grid="2x12" .homecard.createsession layout-grid-columns="4" layout-grid-position="0,0" layout-grid-rows="1" layout-link="createSession" type="createSession" class="#{logged_in_not_logged_in_class}" h2 create session .homebox-info @@ -45,7 +45,7 @@ .homebox-info /! free service level -else - .grid layout-grid="2x12" + .grid layout-grid="2x12" .homecard.createsession layout-grid-columns="4" layout-grid-position="0,0" layout-grid-rows="1" layout-link="createSession" type="createSession" class="#{logged_in_not_logged_in_class}" h2 create session .homebox-info diff --git a/web/app/views/clients/_profile.html.erb b/web/app/views/clients/_profile.html.erb index 2bbc22804..52e3b459a 100644 --- a/web/app/views/clients/_profile.html.erb +++ b/web/app/views/clients/_profile.html.erb @@ -99,20 +99,9 @@
Performance Samples

-
None specified
- - - - - - + <%=render "profile_summary_performance_samples" %> +

@@ -120,39 +109,8 @@
Online Presence

-
None specified
- - - - - - - - - - - - - - - - + + <%=render "profile_summary_online_presence" %>
diff --git a/web/app/views/clients/_profile_online_sample_controls.html.slim b/web/app/views/clients/_profile_edit_presence_controls.html.slim similarity index 89% rename from web/app/views/clients/_profile_online_sample_controls.html.slim rename to web/app/views/clients/_profile_edit_presence_controls.html.slim index 55f59fb39..67e57337d 100644 --- a/web/app/views/clients/_profile_online_sample_controls.html.slim +++ b/web/app/views/clients/_profile_edit_presence_controls.html.slim @@ -65,7 +65,7 @@ td colspan="33.33%": label JamKazam Recordings: td colspan="33.33%": label SoundCloud Recordings (URL): td colspan="33.33%": label YouTube Videos (URL): - tr + tr.add-samples-controls-row td colspan="33.33%" a.btn-add-jk-recording.button-grey BROWSE td colspan="33.33%" @@ -82,7 +82,13 @@ td a.btn-add-youtube-video.button-grey.add-recording-source ADD span.spinner-small - tr - td colspan="33.33%": .sample-list - td colspan="33.33%": .sample-list - td colspan="33.33%": .sample-list \ No newline at end of file + tr.add-samples-list-row + td colspan="33.33%" + .sample-list source-type='jamkazam' + .empty No recordings + td colspan="33.33%" + .sample-list source-type='soundcloud' + .empty No recordings + td colspan="33.33%" + .sample-list source-type='youtube' + .empty No recordings \ No newline at end of file diff --git a/web/app/views/clients/_profile_summary_online_presence.html.slim b/web/app/views/clients/_profile_summary_online_presence.html.slim new file mode 100644 index 000000000..aa1554a08 --- /dev/null +++ b/web/app/views/clients/_profile_summary_online_presence.html.slim @@ -0,0 +1,26 @@ +.no-online-presence.left.online-presence-option.hidden + | None specified +.user-website.left.logo.online-presence-option.hidden + a rel="external" + img.logo src="/assets/content/website-logo.png" +.soundcloud-presence.left.logo.online-presence-option.hidden + a rel="external" + img.logo src="/assets/content/soundcloud-logo.png" +.reverbnation-presence.left.logo.online-presence-option.hidden + a rel="external" + img.logo src="/assets/content/reverbnation-logo.png" +.bandcamp-presence.left.logo.online-presence-option.hidden + a rel="external" + img.logo src="/assets/content/bandcamp-logo.png" +.fandalism-presence.left.logo.online-presence-option.hidden + a rel="external" + img.logo src="/assets/content/fandalism-logo.png" +.youtube-presence.left.logo.online-presence-option.hidden + a rel="external" + img.logo src="/assets/content/youtube-logo.png" +.facebook-presence.left.logo.online-presence-option.hidden + a rel="external" + img.logo src="/assets/content/facebook-logo.png" +.twitter-presence.left.logo.online-presence-option.hidden + a rel="external" + img.logo src="/assets/content/twitter-logo.png" diff --git a/web/app/views/clients/_profile_summary_performance_samples.html.slim b/web/app/views/clients/_profile_summary_performance_samples.html.slim new file mode 100644 index 000000000..8450ba170 --- /dev/null +++ b/web/app/views/clients/_profile_summary_performance_samples.html.slim @@ -0,0 +1,11 @@ +.no-samples.left.performance-sample-option.hidden None specified +.jamkazam-samples.left.logo.performance-sample-option.hidden + img.logo src="/assets/header/logo.png" + br/ +.soundcloud-samples.left.logo.performance-sample-option.hidden + img.logo src="/assets/content/soundcloud-logo.png" + br/ +.youtube-samples.left.logo.performance-sample-option.hidden + img.logo src="/assets/content/youtube-logo.png" + br/ + diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index 9864066b9..dd836cee3 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -9,6 +9,7 @@ <%= render "header" %> +<%= react_component 'BroadcastHolder', {} %> <%= render "home" %> <%= render "footer" %> <%= render "paginator" %> @@ -84,6 +85,7 @@ <%= render 'dialogs/dialogs' %>
+