Merge branch 'develop' into feature/new_session
Conflicts: web/app/assets/javascripts/fakeJamClient.js web/app/assets/javascripts/globals.js web/app/assets/javascripts/trackHelpers.js web/app/assets/javascripts/utils.js web/app/views/dialogs/_dialogs.html.haml
|
|
@ -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
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<%- headers = ['email', 'name', 'unsubscribe_token'] -%>
|
||||
<%= CSV.generate_line headers %><%- @users.each do |user| -%><%= CSV.generate_line([user.email, user.first_name, user.unsubscribe_token]) %><%- end -%>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4,4 +4,4 @@
|
|||
# If you change this key, all old signed cookies will become invalid!
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
JamAdmin::Application.config.secret_token = 'e27a8deff5bc124d1c74cb86ebf38ac4a246091b859bcccf4f8076454e0ff3e04ffc87c9a0f4ddc801c4753e20b2a3cf06e5efc815cfe8e6377f912b737c5f77'
|
||||
JamAdmin::Application.config.secret_token = 'ced345e01611593c1b783bae98e4e56dbaee787747e92a141565f7c61d0ab2c6f98f7396fb4b178258301e2713816e158461af58c14b695901692f91e72b6200'
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ FactoryGirl.define do
|
|||
end
|
||||
|
||||
before(:create) do |user|
|
||||
user.musician_instruments << FactoryGirl.build(:musician_instrument, user: user)
|
||||
user.musician_instruments << FactoryGirl.build(:musician_instrument, player: user)
|
||||
end
|
||||
|
||||
factory :single_user_session do
|
||||
|
|
|
|||
10
db/manifest
|
|
@ -276,6 +276,12 @@ jam_track_duration.sql
|
|||
sales.sql
|
||||
show_whats_next_count.sql
|
||||
recurly_adjustments.sql
|
||||
alter_type_columns.sql
|
||||
user_presences_rename.sql
|
||||
add_genre_type.sql
|
||||
add_description_to_perf_samples.sql
|
||||
alter_genre_player_unique_constraint.sql
|
||||
musician_search.sql
|
||||
signup_hints.sql
|
||||
packaging_notices.sql
|
||||
first_played_jamtrack_at.sql
|
||||
|
|
@ -286,4 +292,6 @@ signing.sql
|
|||
optimized_redeemption.sql
|
||||
optimized_redemption_warn_mode.sql
|
||||
affiliate_partners2.sql
|
||||
broadcast_notifications.sql
|
||||
enhance_band_profile.sql
|
||||
broadcast_notifications.sql
|
||||
broadcast_notifications_fk.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
alter table performance_samples add column description varchar(256) NULL;
|
||||
|
|
@ -0,0 +1 @@
|
|||
alter table genre_players add column genre_type varchar(20) default 'profile';
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE genre_players DROP CONSTRAINT genre_player_uniqkey;
|
||||
ALTER TABLE genre_players ADD CONSTRAINT genre_player_uniqkey UNIQUE (player_id, player_type, genre_id, genre_type);
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE user_presences RENAME COLUMN type to service_type;
|
||||
ALTER TABLE performance_samples RENAME COLUMN type to service_type;
|
||||
|
|
@ -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;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
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;
|
||||
ALTER TABLE bands ADD COLUMN touring_option BOOLEAN DEFAULT FALSE;
|
||||
ALTER TABLE bands ADD COLUMN paid_gigs BOOLEAN DEFAULT FALSE;
|
||||
ALTER TABLE bands ADD COLUMN free_gigs BOOLEAN DEFAULT FALSE;
|
||||
ALTER TABLE bands ADD COLUMN hourly_rate INT DEFAULT 0;
|
||||
ALTER TABLE bands ADD COLUMN gig_minimum INT DEFAULT 0;
|
||||
|
||||
ALTER TABLE musicians_instruments ALTER COLUMN user_id DROP NOT NULL;
|
||||
ALTER TABLE musicians_instruments RENAME COLUMN user_id TO player_id;
|
||||
ALTER TABLE musicians_instruments ADD COLUMN player_type VARCHAR(32) DEFAULT 'user';
|
||||
ALTER TABLE musicians_instruments DROP CONSTRAINT musicians_instruments_user_id_fkey;
|
||||
|
||||
ALTER TABLE performance_samples ALTER COLUMN user_id DROP NOT NULL;
|
||||
ALTER TABLE performance_samples RENAME COLUMN user_id TO player_id;
|
||||
ALTER TABLE performance_samples ADD COLUMN player_type VARCHAR(32) DEFAULT 'user';
|
||||
ALTER TABLE performance_samples DROP CONSTRAINT performance_samples_user_id_fkey;
|
||||
|
||||
ALTER TABLE online_presences ALTER COLUMN user_id DROP NOT NULL;
|
||||
ALTER TABLE online_presences RENAME COLUMN user_id TO player_id;
|
||||
ALTER TABLE online_presences ADD COLUMN player_type VARCHAR(32) DEFAULT 'user';
|
||||
ALTER TABLE online_presences DROP CONSTRAINT online_presences_user_id_fkey;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
CREATE TABLE json_stores (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id VARCHAR(64) REFERENCES users(id) ON DELETE CASCADE,
|
||||
foreign_key1_id VARCHAR(64),
|
||||
data_blob JSON NOT NULL DEFAULT '{}',
|
||||
type VARCHAR(128)
|
||||
);
|
||||
|
||||
CREATE INDEX user_idx ON json_stores(user_id);
|
||||
CREATE INDEX foreign_key1_idx ON json_stores(foreign_key1_id);
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
drop table user_presences;
|
||||
|
||||
CREATE TABLE online_presences (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id VARCHAR(64) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
service_type VARCHAR(100) NOT NULL,
|
||||
username VARCHAR(100) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
|
@ -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'
|
||||
|
|
@ -62,6 +62,7 @@ group :test do
|
|||
gem 'resque_spec' #, :path => "/home/jam/src/resque_spec/"
|
||||
gem 'timecop'
|
||||
gem 'rspec-prof'
|
||||
gem 'time_difference'
|
||||
gem 'byebug'
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
{"container_file": "/var/folders/fk/0ckzmddd4tq28kxbb09vckbr0000gn/T/d20150519-97259-1h1tbhj/jam-track-35.jkz", "version": "0", "coverart": null, "rsa_priv_file": "/var/folders/fk/0ckzmddd4tq28kxbb09vckbr0000gn/T/d20150519-97259-1h1tbhj/skey.pem", "tracks": [{"name": "/var/folders/fk/0ckzmddd4tq28kxbb09vckbr0000gn/T/d20150519-97259-1h1tbhj/7452fa4a-0c55-4cb2-948e-221475d7299c.ogg", "trackName": "track_00"}], "rsa_pub_file": "/var/folders/fk/0ckzmddd4tq28kxbb09vckbr0000gn/T/d20150519-97259-1h1tbhj/pkey.pem", "jamktrack_info": "/var/folders/fk/0ckzmddd4tq28kxbb09vckbr0000gn/T/tmpGdncJS"}
|
||||
|
|
@ -230,6 +230,10 @@ require "jam_ruby/models/broadcast_notification_view"
|
|||
require "jam_ruby/jam_tracks_manager"
|
||||
require "jam_ruby/jam_track_importer"
|
||||
require "jam_ruby/jmep_manager"
|
||||
require "jam_ruby/models/performance_sample"
|
||||
require "jam_ruby/models/online_presence"
|
||||
require "jam_ruby/models/json_store"
|
||||
require "jam_ruby/models/musician_search"
|
||||
|
||||
include Jampb
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module Limits
|
|||
|
||||
# instruments
|
||||
MIN_INSTRUMENTS_PER_MUSICIAN = 1
|
||||
MAX_INSTRUMENTS_PER_MUSICIAN = 5
|
||||
MAX_INSTRUMENTS_PER_MUSICIAN = 1000
|
||||
|
||||
# users
|
||||
USERS_CAN_INVITE = true
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ module JamRuby
|
|||
|
||||
attr_accessible :name, :website, :biography, :city, :state,
|
||||
:country, :original_fpfile_photo, :cropped_fpfile_photo, :cropped_large_fpfile_photo,
|
||||
:cropped_s3_path_photo, :cropped_large_s3_path_photo, :crop_selection_photo, :photo_url, :large_photo_url
|
||||
:cropped_s3_path_photo, :cropped_large_s3_path_photo, :crop_selection_photo, :photo_url, :large_photo_url,
|
||||
:band_type, :band_status, :concert_count, :add_new_members, :play_commitment, :touring_option, :paid_gigs,
|
||||
:free_gigs, :hourly_rate, :gig_minimum
|
||||
|
||||
attr_accessor :updating_photo, :skip_location_validation
|
||||
attr_accessor :updating_photo, :skip_location_validation, :skip_genre_validation
|
||||
|
||||
self.primary_key = 'id'
|
||||
|
||||
|
|
@ -19,12 +21,20 @@ module JamRuby
|
|||
validates :city, presence: true, :unless => :skip_location_validation
|
||||
|
||||
validate :validate_photo_info
|
||||
validate :require_at_least_one_genre
|
||||
validate :require_at_least_one_genre, :unless => :skip_genre_validation
|
||||
validate :limit_max_genres
|
||||
|
||||
before_save :check_lat_lng
|
||||
before_save :check_website_url
|
||||
|
||||
# instruments
|
||||
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", :foreign_key=> 'player_id'
|
||||
has_many :performance_samples, :class_name => "JamRuby::PerformanceSample", :foreign_key=> 'player_id'
|
||||
|
||||
|
||||
# musicians
|
||||
has_many :band_musicians, :class_name => "JamRuby::BandMusician", dependent: :destroy
|
||||
has_many :users, :through => :band_musicians, :class_name => "JamRuby::User"
|
||||
|
|
@ -169,7 +179,7 @@ module JamRuby
|
|||
band = id.blank? ? Band.new : Band.find(id)
|
||||
|
||||
# ensure user updating Band details is a Band member
|
||||
unless band.new_record? || band.users.exists?(user)
|
||||
unless band.new_record? || band.users.exists?(user)
|
||||
raise JamPermissionError, ValidationMessages::USER_NOT_BAND_MEMBER_VALIDATION_ERROR
|
||||
end
|
||||
|
||||
|
|
@ -189,12 +199,33 @@ module JamRuby
|
|||
band.genres = genres
|
||||
end
|
||||
|
||||
band.skip_genre_validation = true unless params[:validate_genres]
|
||||
|
||||
unless band.new_record?
|
||||
OnlinePresence.delete_all(["player_id = ?", band.id])
|
||||
PerformanceSample.delete_all(["player_id = ?", band.id])
|
||||
end
|
||||
|
||||
online_presences = params[:online_presences]
|
||||
if online_presences.present?
|
||||
online_presences.each do |op|
|
||||
new_presence = OnlinePresence.create(band, op, false)
|
||||
band.online_presences << new_presence
|
||||
end
|
||||
end
|
||||
|
||||
performance_samples = params[:performance_samples]
|
||||
if performance_samples.present?
|
||||
performance_samples.each do |ps|
|
||||
band.performance_samples << PerformanceSample.create(band, ps, false)
|
||||
end
|
||||
end
|
||||
|
||||
band
|
||||
end
|
||||
|
||||
# helper method for creating / updating a Band
|
||||
def self.save(user, params)
|
||||
def self.save(user, params)
|
||||
band = build_band(user, params)
|
||||
|
||||
if band.save
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ module JamRuby
|
|||
has_many :playing_sessions, :class_name => "JamRuby::ActiveMusicSession"
|
||||
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "claimed_recording_id", :dependent => :destroy
|
||||
has_many :plays, :class_name => "JamRuby::PlayablePlay", :foreign_key => "claimed_recording_id", :dependent => :destroy
|
||||
has_many :performance_samples, :class_name => "JamRuby::PerformanceSample", :foreign_key => "claimed_recording_id", :dependent => :destroy
|
||||
has_one :share_token, :class_name => "JamRuby::ShareToken", :inverse_of => :shareable, :foreign_key => 'shareable_id', :dependent => :destroy
|
||||
|
||||
validates :name, no_profanity: true, length: {minimum: 3, maximum: 64}, presence: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
module JamRuby
|
||||
class GenrePlayer < ActiveRecord::Base
|
||||
|
||||
PROFILE = 'profile'
|
||||
VIRTUAL_BAND = 'virtual_band'
|
||||
TRADITIONAL_BAND = 'traditional_band'
|
||||
PAID_SESSION = 'paid_sessions'
|
||||
FREE_SESSION = 'free_sessions'
|
||||
COWRITING = 'cowriting'
|
||||
|
||||
self.table_name = "genre_players"
|
||||
|
||||
belongs_to :player, polymorphic: true
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ module JamRuby
|
|||
|
||||
# users
|
||||
has_many :musician_instruments, :class_name => "JamRuby::MusicianInstrument"
|
||||
has_many :users, :through => :musician_instruments, :class_name => "JamRuby::User"
|
||||
has_many :players, :through => :musician_instruments
|
||||
has_many :tracks, :class_name => "JamRuby::Track", :inverse_of => :instrument
|
||||
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :inverse_of => :instrument
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
module JamRuby
|
||||
class JsonStore < ActiveRecord::Base
|
||||
self.table_name = 'json_stores'
|
||||
|
||||
serialize :data_blob, JSON
|
||||
|
||||
before_create do
|
||||
self.data_blob ||= {}
|
||||
end
|
||||
|
||||
after_save do
|
||||
@json = nil
|
||||
end
|
||||
|
||||
attr_accessible :user_id
|
||||
|
||||
belongs_to :user, class_name: "JamRuby::User"
|
||||
|
||||
def json
|
||||
@json ||= self.data_blob
|
||||
end
|
||||
|
||||
def update_json_value(key, val)
|
||||
self.json[key] = val
|
||||
self.update_attribute(:data_blob, self.json)
|
||||
end
|
||||
|
||||
def json_value(key)
|
||||
self.json[key]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -10,7 +10,7 @@ module JamRuby
|
|||
|
||||
# proficiency is 1 = Beginner, 2 = Intermediate, 3 = Expert
|
||||
|
||||
belongs_to :user, :class_name => "JamRuby::User"
|
||||
belongs_to :player, polymorphic: true
|
||||
belongs_to :instrument, :class_name => "JamRuby::Instrument"
|
||||
|
||||
def description
|
||||
|
|
|
|||
|
|
@ -0,0 +1,405 @@
|
|||
module JamRuby
|
||||
class MusicianSearch < JsonStore
|
||||
|
||||
attr_accessor :page_count, :results, :user_counters, :page_number
|
||||
|
||||
ANY_VAL_STR = 'any'
|
||||
ANY_VAL_INT = -1
|
||||
|
||||
PER_PAGE = 10
|
||||
PG_SMALLINT_MAX = 32767
|
||||
|
||||
KEY_GIGS = 'concert_gigs'
|
||||
KEY_STUDIOS = 'studio_sessions'
|
||||
KEY_AGES = 'ages'
|
||||
KEY_SKILL = 'skill_level'
|
||||
KEY_GENRES = 'genres'
|
||||
KEY_INSTRUMENTS = 'instruments'
|
||||
KEY_INTERESTS = 'interests'
|
||||
KEY_SORT_ORDER = 'sort_order'
|
||||
|
||||
SORT_VALS = %W{ latency distance }
|
||||
SORT_ORDERS = {
|
||||
SORT_VALS[0] => 'Latency to Me',
|
||||
SORT_VALS[1] => 'Distance to Me'
|
||||
}
|
||||
|
||||
SKILL_VALS = [ANY_VAL_INT, 1, 2]
|
||||
SKILL_LEVELS = {
|
||||
SKILL_VALS[0] => 'Any',
|
||||
SKILL_VALS[1] => 'Amateur',
|
||||
SKILL_VALS[2] => 'Pro',
|
||||
}
|
||||
|
||||
GIG_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4]
|
||||
GIG_LABELS = {
|
||||
GIG_COUNTS[0] => 'Any',
|
||||
GIG_COUNTS[1] => 'under 10',
|
||||
GIG_COUNTS[2] => '10 to 50',
|
||||
GIG_COUNTS[3] => '50 to 100',
|
||||
GIG_COUNTS[4] => 'over 100'
|
||||
}
|
||||
|
||||
STUDIO_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4]
|
||||
STUDIOS_LABELS = {
|
||||
STUDIO_COUNTS[0] => 'Any',
|
||||
STUDIO_COUNTS[1] => 'under 10',
|
||||
STUDIO_COUNTS[2] => '10 to 50',
|
||||
STUDIO_COUNTS[3] => '50 to 100',
|
||||
STUDIO_COUNTS[4] => 'over 100'
|
||||
}
|
||||
|
||||
AGE_COUNTS = [10, 20, 30, 40, 50]
|
||||
AGES = {
|
||||
AGE_COUNTS[0] => 'Teens',
|
||||
AGE_COUNTS[1] => "20's",
|
||||
AGE_COUNTS[2] => "30's",
|
||||
AGE_COUNTS[3] => "40's",
|
||||
AGE_COUNTS[4] => "50+"
|
||||
}
|
||||
|
||||
INTEREST_VALS = [ANY_VAL_STR,
|
||||
GenrePlayer::VIRTUAL_BAND,
|
||||
GenrePlayer::TRADITIONAL_BAND,
|
||||
GenrePlayer::PAID_SESSION,
|
||||
GenrePlayer::FREE_SESSION,
|
||||
GenrePlayer::COWRITING,
|
||||
]
|
||||
INTERESTS = {
|
||||
INTEREST_VALS[0] => 'Any',
|
||||
INTEREST_VALS[1] => 'Virtual Band',
|
||||
INTEREST_VALS[2] => 'Traditional Band',
|
||||
INTEREST_VALS[3] => 'Paid Sessions',
|
||||
INTEREST_VALS[4] => 'Free Sessions',
|
||||
INTEREST_VALS[5] => 'Co-Writing'
|
||||
}
|
||||
|
||||
INSTRUMENT_PROFICIENCY = {
|
||||
1 => 'Beginner',
|
||||
2 => 'Intermediate',
|
||||
3 => 'Expert',
|
||||
}
|
||||
|
||||
JSON_SCHEMA = {
|
||||
KEY_SORT_ORDER => SORT_VALS[0],
|
||||
KEY_INSTRUMENTS => [],
|
||||
KEY_INTERESTS => INTEREST_VALS[0],
|
||||
KEY_GENRES => [],
|
||||
KEY_GIGS => GIG_COUNTS[0].to_s,
|
||||
KEY_STUDIOS => STUDIO_COUNTS[0].to_s,
|
||||
KEY_SKILL => SKILL_VALS[0].to_s,
|
||||
KEY_AGES => []
|
||||
}
|
||||
JSON_SCHEMA_KEYS = JSON_SCHEMA.keys
|
||||
MULTI_VALUE_KEYS = JSON_SCHEMA.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact
|
||||
SINGLE_VALUE_KEYS = JSON_SCHEMA.keys - MULTI_VALUE_KEYS
|
||||
|
||||
SEARCH_FILTER_META = {
|
||||
per_page: PER_PAGE,
|
||||
filter_keys: {
|
||||
keys: JSON_SCHEMA_KEYS,
|
||||
multi: MULTI_VALUE_KEYS,
|
||||
single: SINGLE_VALUE_KEYS,
|
||||
},
|
||||
sort_order: { keys: SORT_VALS, map: SORT_ORDERS },
|
||||
interests: { keys: INTEREST_VALS, map: INTERESTS },
|
||||
ages: { keys: AGE_COUNTS, map: AGES }
|
||||
}
|
||||
|
||||
def self.user_search_filter(user)
|
||||
unless ms = user.musician_search
|
||||
ms = self.create_search(user)
|
||||
end
|
||||
ms
|
||||
end
|
||||
|
||||
def self.search_filter_json(user)
|
||||
self.user_search_filter(user).json
|
||||
end
|
||||
|
||||
def self.create_search(user)
|
||||
ms = self.new
|
||||
ms.user = user
|
||||
ms.data_blob = JSON_SCHEMA
|
||||
ms.save!
|
||||
ms
|
||||
end
|
||||
|
||||
def _genres(rel)
|
||||
gids = json[KEY_GENRES]
|
||||
unless gids.blank?
|
||||
gidsql = gids.join("','")
|
||||
gpsql = "SELECT player_id FROM genre_players WHERE (player_type = 'JamRuby::User' AND genre_id IN ('#{gidsql}'))"
|
||||
rel = rel.where("users.id IN (#{gpsql})")
|
||||
end
|
||||
rel
|
||||
end
|
||||
|
||||
def _instruments(rel)
|
||||
unless (instruments = json['instruments']).blank?
|
||||
instsql = "SELECT player_id FROM musicians_instruments WHERE (("
|
||||
instsql += instruments.collect do |inst|
|
||||
"instrument_id = '#{inst['instrument_id']}' AND proficiency_level = #{inst['proficiency_level']}"
|
||||
end.join(") OR (")
|
||||
instsql += "))"
|
||||
rel = rel.where("users.id IN (#{instsql})")
|
||||
end
|
||||
rel
|
||||
end
|
||||
|
||||
def _ages(rel)
|
||||
unless (vals = json[KEY_AGES]).blank?
|
||||
return rel if vals.detect { |vv| ANY_VAL_INT == vv }
|
||||
arels = []
|
||||
vals.each do |val|
|
||||
today = Date.today
|
||||
case val.to_i
|
||||
when 10
|
||||
arels << User.where("birth_date >= ? AND birth_date < ?",
|
||||
today - 20.years, today - 10.years)
|
||||
when 20
|
||||
arels << User.where("birth_date >= ? AND birth_date < ?",
|
||||
today - 30.years, today - 20.years)
|
||||
when 30
|
||||
arels << User.where("birth_date >= ? AND birth_date < ?",
|
||||
today - 40.years, today - 50.years)
|
||||
when 40
|
||||
arels << User.where("birth_date >= ? AND birth_date < ?",
|
||||
today - 50.years, today - 40.years)
|
||||
when 50
|
||||
arels << User.where("birth_date <= ?", today - 50.years)
|
||||
end
|
||||
end
|
||||
rel = rel.where("birth_date IS NOT NULL")
|
||||
sql = "(#{arels.map(&:where_values).flatten.join(') OR (')})"
|
||||
rel = rel.where(sql)
|
||||
end
|
||||
rel
|
||||
end
|
||||
|
||||
def _studios(rel)
|
||||
ss = json[KEY_STUDIOS].to_i
|
||||
rel = rel.where('studio_session_count = ?', ss) if 0 <= ss
|
||||
rel
|
||||
end
|
||||
|
||||
def _gigs(rel)
|
||||
gg = json[KEY_GIGS].to_i
|
||||
rel = rel.where('concert_count = ?',gg) if 0 <= gg
|
||||
rel
|
||||
end
|
||||
|
||||
def _skills(rel)
|
||||
if 0 < (val = json[KEY_SKILL].to_i)
|
||||
rel = rel.where(['skill_level = ?', val])
|
||||
end
|
||||
rel
|
||||
end
|
||||
|
||||
def _interests(rel)
|
||||
val = json[KEY_INTERESTS]
|
||||
if val.present? && ANY_VAL_STR != val
|
||||
rel = rel.where("#{val} = ?", true)
|
||||
end
|
||||
rel
|
||||
end
|
||||
|
||||
def _sort_order(rel)
|
||||
val = json[KEY_SORT_ORDER]
|
||||
if SORT_VALS[1] == val
|
||||
locidispid = self.user.last_jam_locidispid || 0
|
||||
my_locid = locidispid / 1000000
|
||||
rel = rel.joins("LEFT JOIN geoiplocations AS my_geo ON my_geo.locid = #{my_locid}")
|
||||
rel = rel.joins("LEFT JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid")
|
||||
rel = rel.group("users.id, my_geo.geog, other_geo.geog")
|
||||
rel = rel.order('st_distance(my_geo.geog, other_geo.geog)')
|
||||
else
|
||||
rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{self.user.id}'")
|
||||
rel = rel.order('current_scores.full_score ASC')
|
||||
end
|
||||
rel
|
||||
end
|
||||
|
||||
def do_search(params={})
|
||||
rel = User.musicians.where('users.id <> ?', self.user.id)
|
||||
rel = self._genres(rel)
|
||||
rel = self._ages(rel)
|
||||
rel = self._studios(rel)
|
||||
rel = self._gigs(rel)
|
||||
rel = self._skills(rel)
|
||||
rel = self._instruments(rel)
|
||||
rel = self._interests(rel)
|
||||
rel = self._sort_order(rel)
|
||||
rel
|
||||
end
|
||||
|
||||
def search_results_page(filter=nil, page=1)
|
||||
if filter
|
||||
self.data_blob = filter
|
||||
self.save
|
||||
else
|
||||
filter = self.data_blob
|
||||
end
|
||||
|
||||
rel = do_search(filter)
|
||||
|
||||
@page_number = [page.to_i, 1].max
|
||||
rel = rel.paginate(:page => @page_number, :per_page => PER_PAGE)
|
||||
|
||||
rel = rel.includes([:instruments, :followings, :friends])
|
||||
@page_count = rel.total_pages
|
||||
|
||||
musician_results(rel.all)
|
||||
end
|
||||
|
||||
def reset_filter
|
||||
self.data_blob = JSON_SCHEMA
|
||||
self.save
|
||||
end
|
||||
|
||||
def reset_search_results
|
||||
reset_filter
|
||||
search_results_page
|
||||
end
|
||||
|
||||
RESULT_FOLLOW = :follows
|
||||
RESULT_FRIEND = :friends
|
||||
|
||||
COUNT_FRIEND = :count_friend
|
||||
COUNT_FOLLOW = :count_follow
|
||||
COUNT_RECORD = :count_record
|
||||
COUNT_SESSION = :count_session
|
||||
COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION]
|
||||
|
||||
def musician_results(_results)
|
||||
@results = _results
|
||||
@user_counters = {} and return self unless user
|
||||
|
||||
@user_counters = @results.inject({}) { |hh,val| hh[val.id] = []; hh }
|
||||
mids = "'#{@results.map(&:id).join("','")}'"
|
||||
|
||||
# this gets counts for each search result on friends/follows/records/sessions
|
||||
@results.each do |uu|
|
||||
counters = { }
|
||||
counters[COUNT_FRIEND] = Friendship.where(:user_id => uu.id).count
|
||||
counters[COUNT_FOLLOW] = Follow.where(:followable_id => uu.id).count
|
||||
counters[COUNT_RECORD] = ClaimedRecording.where(:user_id => uu.id).count
|
||||
counters[COUNT_SESSION] = MusicSession.where(:user_id => uu.id).count
|
||||
@user_counters[uu.id] << counters
|
||||
end
|
||||
|
||||
# this section determines follow/like/friend status for each search result
|
||||
# so that action links can be activated or not
|
||||
rel = User.select("users.id AS uid")
|
||||
rel = rel.joins("LEFT JOIN follows ON follows.user_id = '#{user.id}'")
|
||||
rel = rel.where(["users.id IN (#{mids}) AND follows.followable_id = users.id"])
|
||||
rel.all.each { |val| @user_counters[val.uid] << RESULT_FOLLOW }
|
||||
|
||||
rel = User.select("users.id AS uid")
|
||||
rel = rel.joins("LEFT JOIN friendships AS friends ON friends.friend_id = '#{user.id}'")
|
||||
rel = rel.where(["users.id IN (#{mids}) AND friends.user_id = users.id"])
|
||||
rel.all.each { |val| @user_counters[val.uid] << RESULT_FRIEND }
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _count(musician, key)
|
||||
if mm = @user_counters[musician.id]
|
||||
return mm.detect { |ii| ii.is_a?(Hash) }[key]
|
||||
end if @user_counters
|
||||
0
|
||||
end
|
||||
|
||||
public
|
||||
|
||||
def follow_count(musician)
|
||||
_count(musician, COUNT_FOLLOW)
|
||||
end
|
||||
|
||||
def friend_count(musician)
|
||||
_count(musician, COUNT_FRIEND)
|
||||
end
|
||||
|
||||
def record_count(musician)
|
||||
_count(musician, COUNT_RECORD)
|
||||
end
|
||||
|
||||
def session_count(musician)
|
||||
_count(musician, COUNT_SESSION)
|
||||
end
|
||||
|
||||
def is_friend?(musician)
|
||||
if mm = @user_counters[musician.id]
|
||||
return mm.include?(RESULT_FRIEND)
|
||||
end if @user_counters
|
||||
false
|
||||
end
|
||||
|
||||
def is_follower?(musician)
|
||||
if mm = @user_counters[musician.id]
|
||||
return mm.include?(RESULT_FOLLOW)
|
||||
end if @user_counters
|
||||
false
|
||||
end
|
||||
|
||||
def search_type
|
||||
self.class.to_s
|
||||
end
|
||||
|
||||
def is_blank?
|
||||
self.data_blob == JSON_SCHEMA
|
||||
end
|
||||
|
||||
def description
|
||||
if self.is_blank?
|
||||
return 'Click search button to look for musicians with similar interests, skill levels, etc.'
|
||||
end
|
||||
jj = self.json
|
||||
str = 'Current Search: '
|
||||
str += "Sort = #{SORT_ORDERS[json_value(MusicianSearch::KEY_SORT_ORDER)]}"
|
||||
if (val = jj[KEY_INTERESTS]) != INTEREST_VALS[0]
|
||||
str += "; Interest = #{INTERESTS[val]}"
|
||||
end
|
||||
if (val = jj[KEY_SKILL].to_i) != SKILL_VALS[0]
|
||||
str += "; Skill = #{SKILL_LEVELS[val]}"
|
||||
end
|
||||
if (val = jj[KEY_STUDIOS].to_i) != STUDIO_COUNTS[0]
|
||||
str += "; Studio Sessions = #{STUDIOS_LABELS[val]}"
|
||||
end
|
||||
if (val = jj[KEY_GIGS].to_i) != GIG_COUNTS[0]
|
||||
str += "; Concert Gigs = #{GIG_LABELS[val]}"
|
||||
end
|
||||
val = jj[KEY_AGES].map(&:to_i)
|
||||
val.sort!
|
||||
if !val.blank?
|
||||
str += "; Ages = "
|
||||
val.each_with_index do |vv, idx|
|
||||
str += "#{AGES[vv]}"
|
||||
str += ', ' unless idx==(val.length-1)
|
||||
end
|
||||
end
|
||||
if 0 < (val = jj[KEY_GENRES]).length
|
||||
str += "; Genres = "
|
||||
genres = Genre.where(["id IN (?)", val]).order('description').pluck(:description)
|
||||
genres.each_with_index do |gg, idx|
|
||||
str += "#{gg}"
|
||||
str += ', ' unless idx==(genres.length-1)
|
||||
end
|
||||
end
|
||||
if 0 < (val = jj[KEY_INSTRUMENTS]).length
|
||||
str += "; Instruments = "
|
||||
instr_ids = val.collect { |vv| vv['instrument_id'] }
|
||||
instrs = Instrument.where(["id IN (?)", instr_ids]).order(:description)
|
||||
instrs.each_with_index do |ii, idx|
|
||||
proficiency = val.detect { |vv| vv['instrument_id'] == ii.id }['proficiency_level']
|
||||
str += "#{ii.description} (#{INSTRUMENT_PROFICIENCY[proficiency.to_i]})"
|
||||
str += ', ' unless idx==(instrs.length-1)
|
||||
end
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -57,7 +57,7 @@ module JamRuby
|
|||
|
||||
# remove all notifications related to this session if it's not found
|
||||
if session.nil?
|
||||
Notification.delete_all "(session_id = '#{session_id}')"
|
||||
Notification.delete_all "(session_id = '#{self.session_id}')"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
module JamRuby
|
||||
class OnlinePresence < ActiveRecord::Base
|
||||
|
||||
PERMISSION_MSG = "You do not have permission to perform this operation."
|
||||
|
||||
attr_accessible :player_id, :service_type, :username
|
||||
belongs_to :player, polymorphic: true
|
||||
|
||||
validates :service_type, presence:true, length: {maximum: 100}
|
||||
validates :username, presence:true, length: {maximum: 100}
|
||||
|
||||
validate :username_service_type_unique
|
||||
|
||||
def username_service_type_unique
|
||||
match = OnlinePresence.exists?(:username => self.username, :service_type => self.service_type)
|
||||
raise ConflictError, "Username #{self.username} is already associated with a #{self.service_type} account" if match
|
||||
end
|
||||
|
||||
def self.index(options = {})
|
||||
raise StateError, "The user is not specified." if options[:id].blank?
|
||||
OnlinePresence.where("player_id = ?", options[:id])
|
||||
end
|
||||
|
||||
# Create with target_player (target_player is either user or band):
|
||||
def self.create(target_player, options = {}, save = true)
|
||||
auth_player(target_player, options)
|
||||
raise StateError, "Missing required information" if options[:service_type].blank? || options[:username].blank?
|
||||
|
||||
up = OnlinePresence.new({
|
||||
:player_id => target_player.id,
|
||||
:service_type => options[:service_type],
|
||||
:username => options[:username]
|
||||
})
|
||||
|
||||
up.save! if save
|
||||
up
|
||||
end
|
||||
|
||||
def self.update(target_player, options = {})
|
||||
auth_player(target_player, options)
|
||||
raise StateError, "Missing required information" if options[:service_type].blank? || options[:username].blank? || options[:id].blank?
|
||||
|
||||
up = OnlinePresence.find(options[:id])
|
||||
up.service_type = options[:service_type]
|
||||
up.username = options[:username]
|
||||
up.save!
|
||||
end
|
||||
|
||||
def self.delete(target_player, options = {})
|
||||
id = options[:id]
|
||||
raise StateError, "Missing required information" if id.blank?
|
||||
online_presence = OnlinePresence.find(id)
|
||||
|
||||
if online_presence.player_id != target_player.id
|
||||
raise JamPermissionError, PERMISSION_MSG
|
||||
end
|
||||
|
||||
unless online_presence.nil?
|
||||
OnlinePresence.destroy(id)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def self.auth_player(target_player, options={})
|
||||
if target_player.nil? || options[:player_id] != target_player.id
|
||||
raise JamPermissionError, PERMISSION_MSG
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
module JamRuby
|
||||
class PerformanceSample < ActiveRecord::Base
|
||||
|
||||
PERMISSION_MSG = "You do not have permission to perform this operation."
|
||||
|
||||
attr_accessible :player_id, :service_type, :claimed_recording_id, :service_id, :url, :description
|
||||
|
||||
belongs_to :player, polymorphic: true
|
||||
belongs_to :claimed_recording, :class_name => "JamRuby::ClaimedRecording", :foreign_key => "claimed_recording_id"
|
||||
|
||||
validates :service_type, presence:true, length: {maximum: 100}
|
||||
|
||||
# JamKazam validators
|
||||
validate :claimed_recording_id_present, :if => lambda { |p| p.service_type == "jamkazam" }
|
||||
validate :user_type_recording_unique, :if => lambda { |p| p.service_type == "jamkazam" }
|
||||
|
||||
# Non-JamKazam validators
|
||||
validate :service_id_present, :if => lambda { |p| p.service_type != "jamkazam" }
|
||||
validate :user_type_service_unique, :if => lambda { |p| p.service_type != "jamkazam" }
|
||||
|
||||
def claimed_recording_id_present
|
||||
raise StateError, "Claimed recording is required for JamKazam performance samples" if self.claimed_recording_id.blank?
|
||||
end
|
||||
|
||||
def user_type_recording_unique
|
||||
match = PerformanceSample.exists?(:player_id => self.player_id, :claimed_recording_id => self.claimed_recording_id, :service_type => self.service_type)
|
||||
raise ConflictError, "You already have this JamKazam recording listed as a sample" if match
|
||||
end
|
||||
|
||||
def service_id_present
|
||||
raise StateError, "Service ID is required for non-JamKazam performance samples" if self.service_id.blank?
|
||||
end
|
||||
|
||||
def user_type_service_unique
|
||||
match = PerformanceSample.exists?(:player_id => self.player_id, :service_id => self.service_id, :service_type => self.service_type)
|
||||
raise ConflictError, "You already have this #{self.service_type} sample listed (#{self.service_id})." if match
|
||||
end
|
||||
|
||||
def self.index(options = {})
|
||||
raise JamArgumentError, "The user is not specified." if options[:id].blank?
|
||||
PerformanceSample.where("player_id = ?", options[:id])
|
||||
end
|
||||
|
||||
# Create with target_player (target_player is either user or band):
|
||||
def self.create(target_player, options = {}, save = true)
|
||||
auth_user(target_player, options)
|
||||
raise StateError, "Missing required information" if options[:service_type].blank?
|
||||
|
||||
ps = PerformanceSample.new({
|
||||
:player_id => target_player.id,
|
||||
:service_type => options[:service_type],
|
||||
:claimed_recording_id => options[:claimed_recording_id],
|
||||
:service_id => options[:service_id],
|
||||
:url => options[:url],
|
||||
:description => options[:description]
|
||||
})
|
||||
|
||||
ps.save! if save
|
||||
ps
|
||||
end
|
||||
|
||||
def self.delete(target_player, options = {})
|
||||
raise JamPermissionError, "You do not have permission to perform this operation" if target_player.nil? || options[:player_id] != target_player.id
|
||||
raise StateError, "The performance sample ID is missing." if options[:id].blank?
|
||||
PerformanceSample.destroy(options[:id])
|
||||
end
|
||||
|
||||
private
|
||||
def self.auth_user(target_player, options={})
|
||||
raise JamPermissionError, PERMISSION_MSG if target_player.nil? || options[:player_id] != target_player.id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -2,7 +2,7 @@ module JamRuby
|
|||
|
||||
# not a active_record model; just a search result container
|
||||
class Search
|
||||
attr_accessor :results, :search_type
|
||||
attr_accessor :results, :search_type, :query
|
||||
attr_accessor :user_counters, :page_num, :page_count
|
||||
|
||||
LIMIT = 10
|
||||
|
|
@ -10,82 +10,6 @@ module JamRuby
|
|||
SEARCH_TEXT_TYPES = [:musicians, :bands, :fans]
|
||||
SEARCH_TEXT_TYPE_ID = :search_text_type
|
||||
|
||||
def self.band_search(txt, user = nil)
|
||||
self.text_search({ SEARCH_TEXT_TYPE_ID => :bands, :query => txt }, user)
|
||||
end
|
||||
|
||||
def self.fan_search(txt, user = nil)
|
||||
self.text_search({ SEARCH_TEXT_TYPE_ID => :fans, :query => txt }, user)
|
||||
end
|
||||
|
||||
def self.musician_search(txt, user = nil)
|
||||
self.text_search({ SEARCH_TEXT_TYPE_ID => :musicians, :query => txt }, user)
|
||||
end
|
||||
|
||||
def self.session_invite_search(query, user)
|
||||
srch = Search.new
|
||||
srch.search_type = :session_invite
|
||||
like_str = "%#{query.downcase}%"
|
||||
rel = User
|
||||
.musicians
|
||||
.where(["users.id IN (SELECT friend_id FROM friendships WHERE user_id = '#{user.id}')"])
|
||||
.where(["first_name ILIKE ? OR last_name ILIKE ?", like_str, like_str])
|
||||
.limit(10)
|
||||
.order([:last_name, :first_name])
|
||||
srch.results = rel.all
|
||||
srch
|
||||
end
|
||||
|
||||
def self.text_search(params, user = nil)
|
||||
srch = Search.new
|
||||
unless (params.blank? || params[:query].blank? || 2 > params[:query].length)
|
||||
srch.text_search(params, user)
|
||||
end
|
||||
srch
|
||||
end
|
||||
|
||||
def text_search(params, user = nil)
|
||||
tsquery = Search.create_tsquery(params[:query])
|
||||
return [] if tsquery.blank?
|
||||
|
||||
rel = case params[SEARCH_TEXT_TYPE_ID].to_s
|
||||
when 'bands'
|
||||
@search_type = :bands
|
||||
Band.scoped
|
||||
when 'fans'
|
||||
@search_type = :fans
|
||||
User.fans
|
||||
else
|
||||
@search_type = :musicians
|
||||
User.musicians
|
||||
end
|
||||
@results = rel.where("(name_tsv @@ to_tsquery('jamenglish', ?))", tsquery).limit(10)
|
||||
@results
|
||||
end
|
||||
|
||||
def initialize(search_results=nil)
|
||||
@results = []
|
||||
self
|
||||
end
|
||||
|
||||
def self.create_tsquery(query)
|
||||
return nil if query.blank?
|
||||
|
||||
search_terms = query.split
|
||||
return nil if search_terms.length == 0
|
||||
|
||||
args = nil
|
||||
search_terms.each do |search_term|
|
||||
if args == nil
|
||||
args = search_term
|
||||
else
|
||||
args = args + " & " + search_term
|
||||
end
|
||||
end
|
||||
args = args + ":*"
|
||||
args
|
||||
end
|
||||
|
||||
PARAM_SESSION_INVITE = :srch_sessinv
|
||||
PARAM_MUSICIAN = :srch_m
|
||||
PARAM_BAND = :srch_b
|
||||
|
|
@ -133,164 +57,322 @@ module JamRuby
|
|||
|
||||
DATE_OPTS = [['Today', 'today'], ['This Week', 'week'], ['This Month', 'month'], ['All Time', 'all']]
|
||||
|
||||
def self.order_param(params, keys=M_ORDERING_KEYS)
|
||||
ordering = params[:orderby]
|
||||
ordering.blank? ? keys[0] : keys.detect { |oo| oo.to_s == ordering }
|
||||
|
||||
def initialize(search_results=nil)
|
||||
@results = []
|
||||
self
|
||||
end
|
||||
|
||||
def is_blank?
|
||||
!!@query && @query.empty?
|
||||
end
|
||||
|
||||
# produce a list of musicians (users where musician is true)
|
||||
# params:
|
||||
# instrument - instrument to search for or blank
|
||||
# score_limit - a range specification for score, see M_SCORE_OPTS above.
|
||||
# handled by relation_pagination:
|
||||
# page - page number to fetch (origin 1)
|
||||
# per_page - number of entries per page
|
||||
# handled by order_param:
|
||||
# orderby - what sort of search, also defines order (followed, plays, playing)
|
||||
# previously handled by where_latlng:
|
||||
# distance - defunct!
|
||||
# city - defunct!
|
||||
# remote_ip - defunct!
|
||||
def self.musician_filter(params={}, user=nil)
|
||||
def text_search(params, user = nil)
|
||||
@query = params[:query]
|
||||
tsquery = Search.create_tsquery(params[:query])
|
||||
return [] if tsquery.blank?
|
||||
|
||||
rel = User.musicians # not musicians_geocoded on purpose; we allow 'unknowns' to surface in the search page
|
||||
rel = rel.select('users.*')
|
||||
rel = rel.group('users.id')
|
||||
rel = case params[SEARCH_TEXT_TYPE_ID].to_s
|
||||
when 'bands'
|
||||
@search_type = :bands
|
||||
Band.scoped
|
||||
when 'fans'
|
||||
@search_type = :fans
|
||||
User.fans
|
||||
else
|
||||
@search_type = :musicians
|
||||
User.musicians
|
||||
end
|
||||
@results = rel.where("(name_tsv @@ to_tsquery('jamenglish', ?))", tsquery).limit(10)
|
||||
@results
|
||||
end
|
||||
|
||||
unless (instrument = params[:instrument]).blank?
|
||||
rel = rel.joins("inner JOIN musicians_instruments AS minst ON minst.user_id = users.id")
|
||||
.where(['minst.instrument_id = ?', instrument])
|
||||
class << self
|
||||
def band_search(txt, user = nil)
|
||||
self.text_search({ SEARCH_TEXT_TYPE_ID => :bands, :query => txt }, user)
|
||||
end
|
||||
|
||||
# to find appropriate musicians we need to join users with scores to get to those with no scores or bad scores
|
||||
# weeded out
|
||||
|
||||
# filter on scores using selections from params
|
||||
# see M_SCORE_OPTS
|
||||
score_limit = ANY_SCORE
|
||||
l = params[:score_limit]
|
||||
unless l.nil?
|
||||
score_limit = l
|
||||
def fan_search(txt, user = nil)
|
||||
self.text_search({ SEARCH_TEXT_TYPE_ID => :fans, :query => txt }, user)
|
||||
end
|
||||
|
||||
locidispid = user.nil? ? 0 : (user.last_jam_locidispid || 0)
|
||||
|
||||
# user can override their location with these 3 values
|
||||
country = params[:country]
|
||||
region = params[:region]
|
||||
city = params[:city]
|
||||
|
||||
my_locid = nil # this is used for distance searches only
|
||||
|
||||
if country && region && city
|
||||
geoiplocation = GeoIpLocations.where(countrycode: country, region: region, city: city).first
|
||||
my_locid = geoiplocation.locid
|
||||
def musician_search(txt, user = nil)
|
||||
self.text_search({ SEARCH_TEXT_TYPE_ID => :musicians, :query => txt }, user)
|
||||
end
|
||||
|
||||
unless my_locid
|
||||
my_locid = locidispid/1000000 # if the user didn't specify a location to search on, user their account locidispid
|
||||
def session_invite_search(query, user)
|
||||
srch = Search.new
|
||||
srch.search_type = :session_invite
|
||||
like_str = "%#{query.downcase}%"
|
||||
rel = User
|
||||
.musicians
|
||||
.where(["users.id IN (SELECT friend_id FROM friendships WHERE user_id = '#{user.id}')"])
|
||||
.where(["first_name ILIKE ? OR last_name ILIKE ?", like_str, like_str])
|
||||
.limit(10)
|
||||
.order([:last_name, :first_name])
|
||||
srch.results = rel.all
|
||||
srch
|
||||
end
|
||||
|
||||
if !locidispid.nil? && !user.nil?
|
||||
# score_join of left allows for null scores, whereas score_join of inner requires a score however good or bad
|
||||
# this is ANY_SCORE:
|
||||
score_join = 'left outer' # or 'inner'
|
||||
score_min = nil
|
||||
score_max = nil
|
||||
# these score_min, score_max come from here (doubled): https://jamkazam.atlassian.net/browse/VRFS-1962
|
||||
case score_limit
|
||||
when GOOD_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = nil
|
||||
score_max = 40
|
||||
when MODERATE_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = 40
|
||||
score_max = 70
|
||||
when POOR_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = 80
|
||||
score_max = 100
|
||||
when UNACCEPTABLE_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = 100
|
||||
score_max = nil
|
||||
when SCORED_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = nil
|
||||
score_max = nil
|
||||
when TEST_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = nil
|
||||
score_max = 60
|
||||
when ANY_SCORE
|
||||
# the default of ANY setup above applies
|
||||
def text_search(params, user = nil)
|
||||
srch = Search.new
|
||||
unless (params.blank? || params[:query].blank? || 2 > params[:query].length)
|
||||
srch.text_search(params, user)
|
||||
end
|
||||
srch
|
||||
end
|
||||
|
||||
def create_tsquery(query)
|
||||
return nil if query.blank?
|
||||
|
||||
search_terms = query.split
|
||||
return nil if search_terms.length == 0
|
||||
|
||||
args = nil
|
||||
search_terms.each do |search_term|
|
||||
if args == nil
|
||||
args = search_term
|
||||
else
|
||||
# the default of ANY setup above applies
|
||||
args = args + " & " + search_term
|
||||
end
|
||||
end
|
||||
args = args + ":*"
|
||||
args
|
||||
end
|
||||
def order_param(params, keys=M_ORDERING_KEYS)
|
||||
ordering = params[:orderby]
|
||||
ordering.blank? ? keys[0] : keys.detect { |oo| oo.to_s == ordering }
|
||||
end
|
||||
|
||||
# produce a list of musicians (users where musician is true)
|
||||
# params:
|
||||
# instrument - instrument to search for or blank
|
||||
# score_limit - a range specification for score, see M_SCORE_OPTS above.
|
||||
# handled by relation_pagination:
|
||||
# page - page number to fetch (origin 1)
|
||||
# per_page - number of entries per page
|
||||
# handled by order_param:
|
||||
# orderby - what sort of search, also defines order (followed, plays, playing)
|
||||
# previously handled by where_latlng:
|
||||
# distance - defunct!
|
||||
# city - defunct!
|
||||
# remote_ip - defunct!
|
||||
def musician_filter(params={}, user=nil)
|
||||
|
||||
rel = User.musicians # not musicians_geocoded on purpose; we allow 'unknowns' to surface in the search page
|
||||
rel = rel.select('users.*')
|
||||
rel = rel.group('users.id')
|
||||
|
||||
unless (instrument = params[:instrument]).blank?
|
||||
rel = rel.joins("inner JOIN musicians_instruments AS minst ON minst.player_id = users.id")
|
||||
.where(['minst.instrument_id = ?', instrument])
|
||||
end
|
||||
|
||||
rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{user.id}'")
|
||||
# to find appropriate musicians we need to join users with scores to get to those with no scores or bad scores
|
||||
# weeded out
|
||||
|
||||
rel = rel.joins('LEFT JOIN regions ON regions.countrycode = users.country AND regions.region = users.state')
|
||||
# filter on scores using selections from params
|
||||
# see M_SCORE_OPTS
|
||||
score_limit = ANY_SCORE
|
||||
l = params[:score_limit]
|
||||
unless l.nil?
|
||||
score_limit = l
|
||||
end
|
||||
|
||||
rel = rel.where(['current_scores.full_score > ?', score_min]) unless score_min.nil?
|
||||
rel = rel.where(['current_scores.full_score <= ?', score_max]) unless score_max.nil?
|
||||
locidispid = user.nil? ? 0 : (user.last_jam_locidispid || 0)
|
||||
|
||||
rel = rel.select('current_scores.full_score, current_scores.score, regions.regionname')
|
||||
rel = rel.group('current_scores.full_score, current_scores.score, regions.regionname')
|
||||
# user can override their location with these 3 values
|
||||
country = params[:country]
|
||||
region = params[:region]
|
||||
city = params[:city]
|
||||
|
||||
my_locid = nil # this is used for distance searches only
|
||||
|
||||
if country && region && city
|
||||
geoiplocation = GeoIpLocations.where(countrycode: country, region: region, city: city).first
|
||||
my_locid = geoiplocation.locid
|
||||
end
|
||||
|
||||
unless my_locid
|
||||
my_locid = locidispid/1000000 # if the user didn't specify a location to search on, user their account locidispid
|
||||
end
|
||||
|
||||
if !locidispid.nil? && !user.nil?
|
||||
# score_join of left allows for null scores, whereas score_join of inner requires a score however good or bad
|
||||
# this is ANY_SCORE:
|
||||
score_join = 'left outer' # or 'inner'
|
||||
score_min = nil
|
||||
score_max = nil
|
||||
# these score_min, score_max come from here (doubled): https://jamkazam.atlassian.net/browse/VRFS-1962
|
||||
case score_limit
|
||||
when GOOD_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = nil
|
||||
score_max = 40
|
||||
when MODERATE_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = 40
|
||||
score_max = 70
|
||||
when POOR_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = 80
|
||||
score_max = 100
|
||||
when UNACCEPTABLE_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = 100
|
||||
score_max = nil
|
||||
when SCORED_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = nil
|
||||
score_max = nil
|
||||
when TEST_SCORE
|
||||
score_join = 'inner'
|
||||
score_min = nil
|
||||
score_max = 60
|
||||
when ANY_SCORE
|
||||
# the default of ANY setup above applies
|
||||
else
|
||||
# the default of ANY setup above applies
|
||||
end
|
||||
|
||||
rel = rel.joins("LEFT JOIN current_scores ON current_scores.a_userid = users.id AND current_scores.b_userid = '#{user.id}'")
|
||||
|
||||
rel = rel.joins('LEFT JOIN regions ON regions.countrycode = users.country AND regions.region = users.state')
|
||||
|
||||
rel = rel.where(['current_scores.full_score > ?', score_min]) unless score_min.nil?
|
||||
rel = rel.where(['current_scores.full_score <= ?', score_max]) unless score_max.nil?
|
||||
|
||||
rel = rel.select('current_scores.full_score, current_scores.score, regions.regionname')
|
||||
rel = rel.group('current_scores.full_score, current_scores.score, regions.regionname')
|
||||
end
|
||||
|
||||
ordering = self.order_param(params)
|
||||
case ordering
|
||||
when :latency
|
||||
# nothing to do. the sort added below 'current_scores.score ASC NULLS LAST' handles this
|
||||
when :distance
|
||||
# convert miles to meters for PostGIS functions
|
||||
miles = params[:distance].blank? ? 500 : params[:distance].to_i
|
||||
meters = miles * 1609.34
|
||||
rel = rel.joins("INNER JOIN geoiplocations AS my_geo ON #{my_locid} = my_geo.locid")
|
||||
rel = rel.joins("INNER JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid")
|
||||
rel = rel.where("users.last_jam_locidispid/1000000 IN (SELECT locid FROM geoiplocations WHERE geog && st_buffer((SELECT geog FROM geoiplocations WHERE locid = #{my_locid}), #{meters}))")
|
||||
rel = rel.group("my_geo.geog, other_geo.geog")
|
||||
rel = rel.order('st_distance(my_geo.geog, other_geo.geog)')
|
||||
when :plays # FIXME: double counting?
|
||||
# sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}"
|
||||
rel = rel.select('COUNT(records.id)+COUNT(sessions.id) AS search_play_count')
|
||||
rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.user_id = users.id")
|
||||
rel = rel.joins("LEFT JOIN recordings AS records ON records.owner_id = users.id")
|
||||
rel = rel.order("search_play_count DESC")
|
||||
when :followed
|
||||
rel = rel.joins('left outer join follows on follows.followable_id = users.id')
|
||||
rel = rel.select('count(follows.user_id) as search_follow_count')
|
||||
rel = rel.order('search_follow_count DESC')
|
||||
when :playing
|
||||
rel = rel.joins("inner JOIN connections ON connections.user_id = users.id")
|
||||
rel = rel.where(['connections.aasm_state != ?', 'expired'])
|
||||
end
|
||||
|
||||
if !locidispid.nil? && !user.nil?
|
||||
rel = rel.order('current_scores.full_score ASC NULLS LAST')
|
||||
end
|
||||
|
||||
rel = rel.order('users.created_at DESC')
|
||||
|
||||
rel, page = self.relation_pagination(rel, params)
|
||||
rel = rel.includes([:instruments, :followings, :friends])
|
||||
|
||||
# XXX: DOES THIS MEAN ALL MATCHING USERS ARE RETURNED?
|
||||
objs = rel.all
|
||||
|
||||
srch = Search.new
|
||||
srch.search_type = :musicians_filter
|
||||
srch.page_num, srch.page_count = page, objs.total_pages
|
||||
srch.musician_results_for_user(objs, user)
|
||||
end
|
||||
|
||||
ordering = self.order_param(params)
|
||||
case ordering
|
||||
when :latency
|
||||
# nothing to do. the sort added below 'current_scores.score ASC NULLS LAST' handles this
|
||||
when :distance
|
||||
# convert miles to meters for PostGIS functions
|
||||
miles = params[:distance].blank? ? 500 : params[:distance].to_i
|
||||
meters = miles * 1609.34
|
||||
rel = rel.joins("INNER JOIN geoiplocations AS my_geo ON #{my_locid} = my_geo.locid")
|
||||
rel = rel.joins("INNER JOIN geoiplocations AS other_geo ON users.last_jam_locidispid/1000000 = other_geo.locid")
|
||||
rel = rel.where("users.last_jam_locidispid/1000000 IN (SELECT locid FROM geoiplocations WHERE geog && st_buffer((SELECT geog FROM geoiplocations WHERE locid = #{my_locid}), #{meters}))")
|
||||
rel = rel.group("my_geo.geog, other_geo.geog")
|
||||
rel = rel.order('st_distance(my_geo.geog, other_geo.geog)')
|
||||
def relation_pagination(rel, params)
|
||||
perpage = [(params[:per_page] || M_PER_PAGE).to_i, 100].min
|
||||
page = [params[:page].to_i, 1].max
|
||||
[rel.paginate(:page => page, :per_page => perpage), page]
|
||||
end
|
||||
|
||||
def new_musicians(usr, since_date)
|
||||
# this attempts to find interesting musicians to tell another musician about where interesting
|
||||
# is "has a good score and was created recently"
|
||||
# we're sort of depending upon usr being a musicians_geocoded as well...
|
||||
# this appears to only be called from EmailBatchNewMusician#deliver_batch_sets! which is
|
||||
# an offline process and thus uses the last jam location as "home base"
|
||||
|
||||
locidispid = usr.last_jam_locidispid
|
||||
score_limit = 70
|
||||
limit = 50
|
||||
|
||||
rel = User.musicians_geocoded
|
||||
.where(['users.created_at >= ? AND users.id != ?', since_date, usr.id])
|
||||
.joins('inner join current_scores on users.id = current_scores.a_userid')
|
||||
.where(['current_scores.b_userid = ?', usr.id])
|
||||
.where(['current_scores.full_score <= ?', score_limit])
|
||||
.order('current_scores.full_score') # best scores first
|
||||
.order('users.created_at DESC') # then most recent
|
||||
.limit(limit)
|
||||
|
||||
objs = rel.all.to_a
|
||||
|
||||
if block_given?
|
||||
yield(objs) if 0 < objs.count
|
||||
else
|
||||
return objs
|
||||
end
|
||||
end
|
||||
|
||||
def band_filter(params={}, current_user=nil)
|
||||
rel = Band.scoped
|
||||
|
||||
unless (genre = params[:genre]).blank?
|
||||
rel = Band.joins("RIGHT JOIN genre_players AS bgenres ON bgenres.player_id = bands.id AND bgenres.player_type = 'JamRuby::Band'")
|
||||
.where(['bgenres.genre_id = ? AND bands.id IS NOT NULL', genre])
|
||||
end
|
||||
|
||||
rel = GeoIpLocations.where_latlng(rel, params, current_user)
|
||||
|
||||
sel_str = 'bands.*'
|
||||
case ordering = self.order_param(params, B_ORDERING_KEYS)
|
||||
when :plays # FIXME: double counting?
|
||||
# sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}"
|
||||
rel = rel.select('COUNT(records.id)+COUNT(sessions.id) AS search_play_count')
|
||||
rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.user_id = users.id")
|
||||
rel = rel.joins("LEFT JOIN recordings AS records ON records.owner_id = users.id")
|
||||
rel = rel.order("search_play_count DESC")
|
||||
sel_str = "COUNT(records)+COUNT(msh) AS play_count, #{sel_str}"
|
||||
rel = rel.joins("LEFT JOIN music_sessions AS msh ON msh.band_id = bands.id")
|
||||
.joins("LEFT JOIN recordings AS records ON records.band_id = bands.id")
|
||||
.group("bands.id")
|
||||
.order("play_count DESC, bands.created_at DESC")
|
||||
when :followed
|
||||
rel = rel.joins('left outer join follows on follows.followable_id = users.id')
|
||||
rel = rel.select('count(follows.user_id) as search_follow_count')
|
||||
rel = rel.order('search_follow_count DESC')
|
||||
sel_str = "COUNT(follows) AS search_follow_count, #{sel_str}"
|
||||
rel = rel.joins("LEFT JOIN follows ON follows.followable_id = bands.id")
|
||||
.group("bands.id")
|
||||
.order("COUNT(follows) DESC, bands.created_at DESC")
|
||||
when :playing
|
||||
rel = rel.joins("inner JOIN connections ON connections.user_id = users.id")
|
||||
rel = rel.where(['connections.aasm_state != ?', 'expired'])
|
||||
rel = rel.joins("LEFT JOIN music_sessions AS msh ON msh.band_id = bands.id")
|
||||
.where('msh.music_session_id IS NOT NULL AND msh.session_removed_at IS NULL')
|
||||
.order("bands.created_at DESC")
|
||||
end
|
||||
|
||||
rel = rel.select(sel_str)
|
||||
rel, page = self.relation_pagination(rel, params)
|
||||
rel = rel.includes([{ :users => :instruments }, :genres ])
|
||||
|
||||
objs = rel.all
|
||||
srch = Search.new
|
||||
srch.search_type = :band_filter
|
||||
srch.page_num, srch.page_count = page, objs.total_pages
|
||||
if 1 == page && current_user.bands.present?
|
||||
current_user.bands.order('created_at DESC').each { |bb| objs.unshift(bb) }
|
||||
end if current_user && current_user.is_a?(User)
|
||||
srch.band_results_for_user(objs, current_user)
|
||||
end
|
||||
|
||||
if !locidispid.nil? && !user.nil?
|
||||
rel = rel.order('current_scores.full_score ASC NULLS LAST')
|
||||
end
|
||||
|
||||
rel = rel.order('users.created_at DESC')
|
||||
|
||||
rel, page = self.relation_pagination(rel, params)
|
||||
rel = rel.includes([:instruments, :followings, :friends])
|
||||
|
||||
# XXX: DOES THIS MEAN ALL MATCHING USERS ARE RETURNED?
|
||||
objs = rel.all
|
||||
|
||||
srch = Search.new
|
||||
srch.search_type = :musicians_filter
|
||||
srch.page_num, srch.page_count = page, objs.total_pages
|
||||
srch.musician_results_for_user(objs, user)
|
||||
end
|
||||
|
||||
def self.relation_pagination(rel, params)
|
||||
perpage = [(params[:per_page] || M_PER_PAGE).to_i, 100].min
|
||||
page = [params[:page].to_i, 1].max
|
||||
[rel.paginate(:page => page, :per_page => perpage), page]
|
||||
end
|
||||
|
||||
|
||||
RESULT_FOLLOW = :follows
|
||||
RESULT_FRIEND = :friends
|
||||
|
|
@ -399,77 +481,7 @@ module JamRuby
|
|||
false
|
||||
end
|
||||
|
||||
def self.new_musicians(usr, since_date)
|
||||
# this attempts to find interesting musicians to tell another musician about where interesting
|
||||
# is "has a good score and was created recently"
|
||||
# we're sort of depending upon usr being a musicians_geocoded as well...
|
||||
# this appears to only be called from EmailBatchNewMusician#deliver_batch_sets! which is
|
||||
# an offline process and thus uses the last jam location as "home base"
|
||||
|
||||
locidispid = usr.last_jam_locidispid
|
||||
score_limit = 70
|
||||
limit = 50
|
||||
|
||||
rel = User.musicians_geocoded
|
||||
.where(['users.created_at >= ? AND users.id != ?', since_date, usr.id])
|
||||
.joins('inner join current_scores on users.id = current_scores.a_userid')
|
||||
.where(['current_scores.b_userid = ?', usr.id])
|
||||
.where(['current_scores.full_score <= ?', score_limit])
|
||||
.order('current_scores.full_score') # best scores first
|
||||
.order('users.created_at DESC') # then most recent
|
||||
.limit(limit)
|
||||
|
||||
objs = rel.all.to_a
|
||||
|
||||
if block_given?
|
||||
yield(objs) if 0 < objs.count
|
||||
else
|
||||
return objs
|
||||
end
|
||||
end
|
||||
|
||||
def self.band_filter(params={}, current_user=nil)
|
||||
rel = Band.scoped
|
||||
|
||||
unless (genre = params[:genre]).blank?
|
||||
rel = Band.joins("RIGHT JOIN genre_players AS bgenres ON bgenres.player_id = bands.id AND bgenres.player_type = 'JamRuby::Band'")
|
||||
.where(['bgenres.genre_id = ? AND bands.id IS NOT NULL', genre])
|
||||
end
|
||||
|
||||
rel = GeoIpLocations.where_latlng(rel, params, current_user)
|
||||
|
||||
sel_str = 'bands.*'
|
||||
case ordering = self.order_param(params, B_ORDERING_KEYS)
|
||||
when :plays # FIXME: double counting?
|
||||
sel_str = "COUNT(records)+COUNT(msh) AS play_count, #{sel_str}"
|
||||
rel = rel.joins("LEFT JOIN music_sessions AS msh ON msh.band_id = bands.id")
|
||||
.joins("LEFT JOIN recordings AS records ON records.band_id = bands.id")
|
||||
.group("bands.id")
|
||||
.order("play_count DESC, bands.created_at DESC")
|
||||
when :followed
|
||||
sel_str = "COUNT(follows) AS search_follow_count, #{sel_str}"
|
||||
rel = rel.joins("LEFT JOIN follows ON follows.followable_id = bands.id")
|
||||
.group("bands.id")
|
||||
.order("COUNT(follows) DESC, bands.created_at DESC")
|
||||
when :playing
|
||||
rel = rel.joins("LEFT JOIN music_sessions AS msh ON msh.band_id = bands.id")
|
||||
.where('msh.music_session_id IS NOT NULL AND msh.session_removed_at IS NULL')
|
||||
.order("bands.created_at DESC")
|
||||
end
|
||||
|
||||
rel = rel.select(sel_str)
|
||||
rel, page = self.relation_pagination(rel, params)
|
||||
rel = rel.includes([{ :users => :instruments }, :genres ])
|
||||
|
||||
objs = rel.all
|
||||
srch = Search.new
|
||||
srch.search_type = :band_filter
|
||||
srch.page_num, srch.page_count = page, objs.total_pages
|
||||
if 1 == page && current_user.bands.present?
|
||||
current_user.bands.order('created_at DESC').each { |bb| objs.unshift(bb) }
|
||||
end if current_user && current_user.is_a?(User)
|
||||
srch.band_results_for_user(objs, current_user)
|
||||
end
|
||||
|
||||
def band_results_for_user(_results, user)
|
||||
@results = _results
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ module JamRuby
|
|||
has_many :received_friend_requests, :class_name => "JamRuby::FriendRequest", :foreign_key => 'friend_id'
|
||||
|
||||
# instruments
|
||||
has_many :musician_instruments, :class_name => "JamRuby::MusicianInstrument"
|
||||
has_many :musician_instruments, :class_name => "JamRuby::MusicianInstrument", :foreign_key=> 'player_id'
|
||||
has_many :instruments, :through => :musician_instruments, :class_name => "JamRuby::Instrument"
|
||||
|
||||
# bands
|
||||
|
|
@ -165,6 +165,11 @@ module JamRuby
|
|||
# This causes the authenticate method to be generated (among other stuff)
|
||||
#has_secure_password
|
||||
|
||||
has_many :online_presences, :class_name => "JamRuby::OnlinePresence", :foreign_key=> 'player_id'
|
||||
has_many :performance_samples, :class_name => "JamRuby::PerformanceSample", :foreign_key=> 'player_id'
|
||||
|
||||
has_one :musician_search, :class_name => 'JamRuby::MusicianSearch'
|
||||
|
||||
before_save :create_remember_token, :if => :should_validate_password?
|
||||
before_save :stringify_avatar_info , :if => :updating_avatar
|
||||
|
||||
|
|
@ -359,7 +364,7 @@ module JamRuby
|
|||
|
||||
def age
|
||||
now = Time.now.utc.to_date
|
||||
self.birth_date.nil? ? "unspecified" : now.year - self.birth_date.year - (self.birth_date.to_date.change(:year => now.year) > now ? 1 : 0)
|
||||
self.birth_date.nil? ? "" : now.year - self.birth_date.year - (self.birth_date.to_date.change(:year => now.year) > now ? 1 : 0)
|
||||
end
|
||||
|
||||
def session_count
|
||||
|
|
@ -651,13 +656,45 @@ module JamRuby
|
|||
return recordings
|
||||
end
|
||||
|
||||
def update_genres(gids)
|
||||
def update_genres(gids, genre_type)
|
||||
unless self.new_record?
|
||||
GenrePlayer.delete_all(["player_id = ? AND player_type = ?",
|
||||
self.id, self.class.name])
|
||||
GenrePlayer.delete_all(["player_id = ? AND player_type = ? AND genre_type = ?",
|
||||
self.id, self.class.name, genre_type])
|
||||
end
|
||||
|
||||
gids.each do |gid|
|
||||
self.genres << Genre.find_by_id(gid)
|
||||
genre_player = GenrePlayer.new
|
||||
genre_player.player_id = self.id
|
||||
genre_player.player_type = self.class.name
|
||||
genre_player.genre_id = gid
|
||||
genre_player.genre_type = genre_type
|
||||
self.genre_players << genre_player
|
||||
end
|
||||
end
|
||||
|
||||
def update_online_presences(online_presences)
|
||||
unless self.new_record?
|
||||
OnlinePresence.delete_all(["player_id = ?", self.id])
|
||||
end
|
||||
|
||||
unless online_presences.nil?
|
||||
online_presences.each do |op|
|
||||
new_presence = OnlinePresence.create(self, op, false)
|
||||
self.online_presences << new_presence
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_performance_samples(performance_samples)
|
||||
unless self.new_record?
|
||||
PerformanceSample.delete_all(["player_id = ?", self.id])
|
||||
end
|
||||
|
||||
unless performance_samples.nil?
|
||||
performance_samples.each do |ps|
|
||||
new_sample = PerformanceSample.create(self, ps, false)
|
||||
self.performance_samples << new_sample
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -665,14 +702,14 @@ module JamRuby
|
|||
def update_instruments(instruments)
|
||||
# delete all instruments for this user first
|
||||
unless self.new_record?
|
||||
MusicianInstrument.delete_all(["user_id = ?", self.id])
|
||||
MusicianInstrument.delete_all(["player_id = ?", self.id])
|
||||
end
|
||||
|
||||
# loop through each instrument in the array and save to the db
|
||||
instruments.each do |musician_instrument_param|
|
||||
instrument = Instrument.find(musician_instrument_param[:instrument_id])
|
||||
musician_instrument = MusicianInstrument.new
|
||||
musician_instrument.user = self
|
||||
musician_instrument.player = self
|
||||
musician_instrument.instrument = instrument
|
||||
musician_instrument.proficiency_level = musician_instrument_param[:proficiency_level]
|
||||
musician_instrument.priority = musician_instrument_param[:priority]
|
||||
|
|
@ -999,7 +1036,7 @@ module JamRuby
|
|||
instruments.each do |musician_instrument_param|
|
||||
instrument = Instrument.find(musician_instrument_param[:instrument_id])
|
||||
musician_instrument = MusicianInstrument.new
|
||||
musician_instrument.user = user
|
||||
musician_instrument.player = user
|
||||
musician_instrument.instrument = instrument
|
||||
musician_instrument.proficiency_level = musician_instrument_param[:proficiency_level]
|
||||
musician_instrument.priority = musician_instrument_param[:priority]
|
||||
|
|
@ -1150,13 +1187,13 @@ module JamRuby
|
|||
end
|
||||
|
||||
unless user.new_record?
|
||||
MusicianInstrument.delete_all(["user_id = ?", user.id])
|
||||
MusicianInstrument.delete_all(["player_id = ?", user.id])
|
||||
end
|
||||
|
||||
instruments.each do |musician_instrument_param|
|
||||
instrument = Instrument.find(musician_instrument_param[:instrument_id])
|
||||
musician_instrument = MusicianInstrument.new
|
||||
musician_instrument.user = user
|
||||
musician_instrument.player = user
|
||||
musician_instrument.instrument = instrument
|
||||
musician_instrument.proficiency_level = musician_instrument_param[:proficiency_level]
|
||||
musician_instrument.priority = musician_instrument_param[:priority]
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ FactoryGirl.define do
|
|||
before(:create) do |user, evaluator|
|
||||
if evaluator.specific_instruments
|
||||
evaluator.specific_instruments.each do |instrument|
|
||||
user.musician_instruments << FactoryGirl.build(:musician_instrument, user: user, instrument: instrument)
|
||||
user.musician_instruments << FactoryGirl.build(:musician_instrument, player: user, instrument: instrument)
|
||||
end
|
||||
else
|
||||
user.musician_instruments << FactoryGirl.build(:musician_instrument, user: user)
|
||||
user.musician_instruments << FactoryGirl.build(:musician_instrument, player: user)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -832,4 +832,5 @@ FactoryGirl.define do
|
|||
factory :affiliate_legalese, class: 'JamRuby::AffiliateLegalese' do
|
||||
legalese Faker::Lorem.paragraphs(6).join("\n\n")
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ describe ConnectionManager, no_transaction: true do
|
|||
client_id = "client_id1"
|
||||
user_id = create_user("test", "user1", "user1@jamkazam.com")
|
||||
user = User.find(user_id)
|
||||
user.musician_instruments << FactoryGirl.build(:musician_instrument, user: user)
|
||||
user.musician_instruments << FactoryGirl.build(:musician_instrument, player: user)
|
||||
user.save!
|
||||
user = nil
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ require 'spec_helper'
|
|||
describe 'Band search' do
|
||||
|
||||
before(:each) do
|
||||
Band.delete_all
|
||||
@bands = []
|
||||
@bands << @band1 = FactoryGirl.create(:band)
|
||||
@bands << @band2 = FactoryGirl.create(:band)
|
||||
|
|
@ -31,6 +32,8 @@ describe 'Band search' do
|
|||
# the ordering should be create_at since no followers exist
|
||||
expect(Follow.count).to eq(0)
|
||||
results = Search.band_filter({ :per_page => Band.count })
|
||||
|
||||
rbands = @bands.reverse
|
||||
results.results.each_with_index do |uu, idx|
|
||||
expect(uu.id).to eq(@bands.reverse[idx].id)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,6 +19,21 @@ describe Band do
|
|||
}
|
||||
}
|
||||
|
||||
describe 'with instruments' do
|
||||
it 'builds with instruments' do
|
||||
band.musician_instruments << FactoryGirl.build(:musician_instrument, player: band)
|
||||
band.musician_instruments.should have(1).items
|
||||
band.instruments.should have(1).items
|
||||
end
|
||||
|
||||
it 'creates with instruments' do
|
||||
FactoryGirl.create(:musician_instrument, player: band)
|
||||
band.reload
|
||||
band.musician_instruments.should have(1).items
|
||||
band.instruments.should have(1).items
|
||||
end
|
||||
end
|
||||
|
||||
describe 'website update' do
|
||||
it 'should have http prefix on website url' do
|
||||
band.website = 'example.com'
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ describe EmailBatchScheduledSessions do
|
|||
4.downto(1) do |nn|
|
||||
uu = FactoryGirl.create(:user, :last_jam_locidispid => 6, :last_jam_addr => 6)
|
||||
uu.musician_instruments << FactoryGirl.build(:musician_instrument,
|
||||
user: uu,
|
||||
player: uu,
|
||||
instrument: instruments.sample,
|
||||
proficiency_level: 2)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,79 +1,206 @@
|
|||
require 'spec_helper'
|
||||
require 'time_difference'
|
||||
|
||||
describe 'Musician search' do
|
||||
|
||||
before(:all) do
|
||||
User.delete_all
|
||||
describe 'Musician Search Model' do
|
||||
|
||||
let!(:searcher) { FactoryGirl.create(:austin_user) }
|
||||
let!(:search) { MusicianSearch.create_search(searcher) }
|
||||
|
||||
let!(:austin_user) { FactoryGirl.create(:austin_user) }
|
||||
let!(:dallas_user) { FactoryGirl.create(:dallas_user) }
|
||||
let!(:miami_user) { FactoryGirl.create(:miami_user) }
|
||||
let!(:seattle_user) { FactoryGirl.create(:seattle_user) }
|
||||
|
||||
let!(:user_types) { [:austin_user, :dallas_user, :miami_user, :seattle_user] }
|
||||
|
||||
describe "creates search obj" do
|
||||
before(:all) do
|
||||
User.delete_all
|
||||
end
|
||||
|
||||
it "associates to user" do
|
||||
expect(search.user).to eq(searcher)
|
||||
searcher.reload
|
||||
expect(searcher.musician_search).to eq(search)
|
||||
end
|
||||
|
||||
it "sets json" do
|
||||
search.update_json_value(MusicianSearch::KEY_GIGS, MusicianSearch::GIG_COUNTS[1])
|
||||
expect(search.json[MusicianSearch::KEY_GIGS]).to eq(MusicianSearch::GIG_COUNTS[1])
|
||||
end
|
||||
end
|
||||
|
||||
describe "filtering criteria" do
|
||||
before(:all) do
|
||||
User.delete_all
|
||||
end
|
||||
# it "filters musicians" do
|
||||
# expect(search.do_search(per_page: User.musicians.count).count).to eq(User.musicians.count)
|
||||
# end
|
||||
|
||||
describe "filters by age" do
|
||||
before(:all) do
|
||||
@users = []
|
||||
today = Date.today
|
||||
MusicianSearch::AGE_COUNTS.each_with_index do |age, idx|
|
||||
dd = today - age.years - 1.day
|
||||
@users << FactoryGirl.create(:austin_user, :birth_date => dd)
|
||||
@users << FactoryGirl.create(:dallas_user, :birth_date => dd)
|
||||
@users << FactoryGirl.create(:miami_user, :birth_date => dd)
|
||||
@users << FactoryGirl.create(:seattle_user, :birth_date => dd)
|
||||
end
|
||||
end
|
||||
|
||||
it "filters by one age" do
|
||||
age = MusicianSearch::AGE_COUNTS[0]
|
||||
search.update_json_value(MusicianSearch::KEY_AGES, [age])
|
||||
today = Date.today.to_time
|
||||
search.do_search.all.each do |uu|
|
||||
diff = TimeDifference.between(uu.birth_date.to_time, today).in_years
|
||||
expect(diff).to be >= age
|
||||
expect(diff).to be < MusicianSearch::AGE_COUNTS[1]
|
||||
end
|
||||
end
|
||||
|
||||
it "filters by multiple ages" do
|
||||
ages = MusicianSearch::AGE_COUNTS[0..2]
|
||||
search.update_json_value(MusicianSearch::KEY_AGES, ages[0..1])
|
||||
today = Date.today.to_time
|
||||
search.do_search.all.each do |uu|
|
||||
diff = TimeDifference.between(uu.birth_date.to_time, today).in_years
|
||||
expect(diff).to be >= ages.first
|
||||
expect(diff).to be < ages.last
|
||||
end
|
||||
end
|
||||
|
||||
it "skips filtering by ages" do
|
||||
search.update_json_value(MusicianSearch::KEY_AGES, [MusicianSearch::ANY_VAL_INT])
|
||||
search.do_search.to_sql =~ /(birth_date)/
|
||||
expect($1).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe "filtering by gig" do
|
||||
before(:all) do
|
||||
user_types.each do |utype|
|
||||
FactoryGirl.create(utype, :concert_count => MusicianSearch::GIG_COUNTS[1])
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores gig count if any selected" do
|
||||
search.update_json_value(MusicianSearch::KEY_GIGS, MusicianSearch::GIG_COUNTS[0])
|
||||
expect(search.do_search.count).to eq(User.musicians.count - 1) # searcher is musician
|
||||
end
|
||||
|
||||
it "filters by gig count" do
|
||||
search.update_json_value(MusicianSearch::KEY_GIGS, MusicianSearch::GIG_COUNTS[1])
|
||||
expect(search.do_search.count).to eq(user_types.count)
|
||||
end
|
||||
end
|
||||
|
||||
describe "filtering by studio" do
|
||||
before(:all) do
|
||||
user_types.each do |utype|
|
||||
FactoryGirl.create(utype, :studio_session_count => MusicianSearch::STUDIO_COUNTS[1])
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores studio count if any selected" do
|
||||
search.update_json_value(MusicianSearch::KEY_STUDIOS, MusicianSearch::STUDIO_COUNTS[0])
|
||||
expect(search.do_search.count).to eq(User.musicians.count - 1)
|
||||
end
|
||||
|
||||
it "filters by studio count" do
|
||||
search.update_json_value(MusicianSearch::KEY_STUDIOS, MusicianSearch::STUDIO_COUNTS[1])
|
||||
expect(search.do_search.count).to eq(user_types.count)
|
||||
end
|
||||
end
|
||||
|
||||
describe "filters skills" do
|
||||
before(:all) do
|
||||
MusicianSearch::SKILL_VALS.each do |val|
|
||||
user_types.each { |utype| FactoryGirl.create(utype, :skill_level => val) }
|
||||
end
|
||||
end
|
||||
|
||||
it "get expected number per skill" do
|
||||
search.update_json_value(MusicianSearch::KEY_SKILL, MusicianSearch::SKILL_VALS[1])
|
||||
expect(search.do_search.count).to eq(user_types.count)
|
||||
end
|
||||
end
|
||||
|
||||
describe "filters interests" do
|
||||
before(:all) do
|
||||
MusicianSearch::INTEREST_VALS[1..-1].each do |val|
|
||||
user_types.each { |utype| FactoryGirl.create(utype, val => true) }
|
||||
end
|
||||
end
|
||||
|
||||
it "get expected number per interest" do
|
||||
search.update_json_value(MusicianSearch::KEY_INTERESTS, MusicianSearch::INTEREST_VALS[1])
|
||||
expect(search.do_search.count).to eq(user_types.count)
|
||||
end
|
||||
end
|
||||
|
||||
describe "filters genres" do
|
||||
before(:all) do
|
||||
user_types.each do |utype|
|
||||
uu = FactoryGirl.create(utype)
|
||||
uu.update_genres([Genre.first.id, Genre.last.id], GenrePlayer::PROFILE)
|
||||
end
|
||||
end
|
||||
|
||||
it "gets expected number of users" do
|
||||
search.update_json_value(MusicianSearch::KEY_GENRES, [Genre.first.id, Genre.last.id])
|
||||
expect(search.do_search.count).to eq(user_types.count)
|
||||
end
|
||||
end
|
||||
|
||||
describe "filters instruments" do
|
||||
before(:all) do
|
||||
instruments = Instrument.first(user_types.count).collect do |inst|
|
||||
{ instrument_id: inst.id, proficiency_level: 2, priority: 1 }
|
||||
end
|
||||
user_types[0..2].each do |utype|
|
||||
uu = FactoryGirl.create(utype)
|
||||
uu.update_instruments(instruments)
|
||||
end
|
||||
end
|
||||
|
||||
it "gets expected number of users" do
|
||||
instjson = [{ instrument_id: Instrument.first.id, proficiency_level: 2 },
|
||||
{ instrument_id: Instrument.first(2)[1].id, proficiency_level: 2 }
|
||||
]
|
||||
search.update_json_value(MusicianSearch::KEY_INSTRUMENTS, instjson)
|
||||
expect(search.do_search.count).to eq(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# need a data set with actual distances
|
||||
describe "test set A" do
|
||||
describe "sort order by distance" do
|
||||
before(:all) do
|
||||
User.delete_all
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
before(:each) do
|
||||
create_phony_database
|
||||
end
|
||||
|
||||
let!(:austin_user) { FactoryGirl.create(:austin_user) }
|
||||
let!(:dallas_user) { FactoryGirl.create(:dallas_user) }
|
||||
let!(:miami_user) { FactoryGirl.create(:miami_user) }
|
||||
let!(:seattle_user) { FactoryGirl.create(:seattle_user) }
|
||||
|
||||
describe "search on distance" do
|
||||
|
||||
it "finds self when very local search" do
|
||||
Search.musician_filter({distance: 1, orderby: 'distance'}, austin_user).results.should == [austin_user] # just to see that distance is 0 to self
|
||||
Search.musician_filter({distance: 1, orderby: 'distance'}, dallas_user).results.should == [dallas_user] # just to see that distance is 0 to self
|
||||
Search.musician_filter({distance: 1, orderby: 'distance'}, miami_user).results.should == [miami_user] # just to see that distance is 0 to self
|
||||
Search.musician_filter({distance: 1, orderby: 'distance'}, seattle_user).results.should == [seattle_user] # just to see that distance is 0 to self
|
||||
end
|
||||
|
||||
it "finds dallas when in range of austin" do
|
||||
expected_results = [austin_user, dallas_user]
|
||||
|
||||
Search.musician_filter({distance: 500, orderby: 'distance'}, austin_user).results.should == expected_results
|
||||
Search.musician_filter({distance: 100, orderby: 'distance'}, austin_user).results.should == [austin_user]
|
||||
end
|
||||
|
||||
it "finds miami when in range of austin" do
|
||||
expected_results = [austin_user, dallas_user, miami_user]
|
||||
|
||||
Search.musician_filter({distance: 1500, orderby: 'distance'}, austin_user).results.should == expected_results
|
||||
Search.musician_filter({distance: 300, orderby: 'distance'}, austin_user).results.should == [austin_user, dallas_user]
|
||||
Search.musician_filter({distance: 100, orderby: 'distance'}, austin_user).results.should == [austin_user]
|
||||
end
|
||||
|
||||
it "finds seattle when in range of austin" do
|
||||
expected_results = [austin_user, dallas_user, miami_user, seattle_user]
|
||||
|
||||
Search.musician_filter({distance: 2000, orderby: 'distance'}, austin_user).results.should == expected_results
|
||||
Search.musician_filter({distance: 1500, orderby: 'distance'}, austin_user).results.should == [austin_user, dallas_user, miami_user]
|
||||
Search.musician_filter({distance: 300, orderby: 'distance'}, austin_user).results.should == [austin_user, dallas_user]
|
||||
Search.musician_filter({distance: 100, orderby: 'distance'}, austin_user).results.should == [austin_user]
|
||||
end
|
||||
|
||||
it "finds austin & dallas by user-specified location when in range" do
|
||||
Search.musician_filter({distance: 500, orderby: 'distance', city: 'Austin', region: 'TX', country: 'US'}, austin_user).results.should == [austin_user, dallas_user]
|
||||
end
|
||||
|
||||
it "finds dallas & austin by user-specified location when in range" do
|
||||
Search.musician_filter({distance: 500, orderby: 'distance', city: 'Dallas', region: 'TX', country: 'US'}, austin_user).results.should == [dallas_user, austin_user]
|
||||
end
|
||||
|
||||
it "finds miami user-specified location when in range" do
|
||||
Search.musician_filter({distance: 300, orderby: 'distance', city: 'Tampa', region: 'FL', country: 'US'}, austin_user).results.should == [miami_user]
|
||||
end
|
||||
|
||||
it "finds all users with user-specified location when in range" do
|
||||
Search.musician_filter({distance: 2500, orderby: 'distance', city: 'Tampa', region: 'FL', country: 'US'}, austin_user).results.should == [miami_user, dallas_user, austin_user, seattle_user]
|
||||
end
|
||||
it "sorts by distance" do
|
||||
musician_search = MusicianSearch.create_search(searcher)
|
||||
musician_search.update_json_value(MusicianSearch::KEY_SORT_ORDER, MusicianSearch::SORT_VALS[1])
|
||||
results = musician_search.do_search
|
||||
expect(results[0].id).to eq(austin_user.id)
|
||||
expect(results[1].id).to eq(dallas_user.id)
|
||||
expect(results[2].id).to eq(miami_user.id)
|
||||
expect(results[3].id).to eq(seattle_user.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "test set B" do
|
||||
|
||||
describe "sort order by latency" do
|
||||
before(:each) do
|
||||
# @geocode1 = FactoryGirl.create(:geocoder)
|
||||
# @geocode2 = FactoryGirl.create(:geocoder)
|
||||
User.delete_all
|
||||
t = Time.now - 10.minute
|
||||
|
||||
@user1 = FactoryGirl.create(:user, created_at: t+1.minute, last_jam_locidispid: 1)
|
||||
|
|
@ -92,13 +219,6 @@ describe 'Musician search' do
|
|||
@musicians << @user5
|
||||
@musicians << @user6
|
||||
|
||||
@geomusicians = []
|
||||
@geomusicians << @user1
|
||||
@geomusicians << @user2
|
||||
@geomusicians << @user3
|
||||
@geomusicians << @user4
|
||||
@geomusicians << @user5
|
||||
|
||||
# from these scores:
|
||||
# user1 has scores other users in user1 location, and with user2, user3, user4
|
||||
# user2 has scores with users in user3 and user4 location
|
||||
|
|
@ -112,318 +232,83 @@ describe 'Musician search' do
|
|||
Score.createx(2, 'b', 2, 4, 'd', 4, 70)
|
||||
end
|
||||
|
||||
|
||||
context 'default filter settings' do
|
||||
|
||||
it "finds all musicians" do
|
||||
# expects all the musicians (geocoded)
|
||||
results = Search.musician_filter({score_limit: Search::TEST_SCORE})
|
||||
results.search_type.should == :musicians_filter
|
||||
results.results.count.should == @musicians.length
|
||||
results.results.should eq @musicians.reverse
|
||||
end
|
||||
|
||||
it "finds all musicians page 1" do
|
||||
# expects all the musicians
|
||||
results = Search.musician_filter({page: 1, score_limit: Search::TEST_SCORE})
|
||||
results.search_type.should == :musicians_filter
|
||||
results.results.count.should == @musicians.length
|
||||
results.results.should eq @musicians.reverse
|
||||
end
|
||||
|
||||
it "finds all musicians page 2" do
|
||||
# expects no musicians (all fit on page 1)
|
||||
results = Search.musician_filter({page: 2, score_limit: Search::TEST_SCORE})
|
||||
results.search_type.should == :musicians_filter
|
||||
results.results.count.should == 0
|
||||
end
|
||||
|
||||
it "finds all musicians page 1 per_page 3" do
|
||||
# expects three of the musicians
|
||||
results = Search.musician_filter({per_page: 3, score_limit: Search::TEST_SCORE})
|
||||
results.search_type.should == :musicians_filter
|
||||
results.results.count.should == 3
|
||||
results.results.should eq @musicians.reverse.slice(0, 3)
|
||||
end
|
||||
|
||||
it "finds all musicians page 2 per_page 3" do
|
||||
# expects two of the musicians
|
||||
results = Search.musician_filter({page: 2, per_page: 3, score_limit: Search::TEST_SCORE})
|
||||
results.search_type.should == :musicians_filter
|
||||
results.results.count.should == 3
|
||||
results.results.should eq @musicians.reverse.slice(3, 3)
|
||||
end
|
||||
|
||||
it "finds all musicians page 3 per_page 3" do
|
||||
# expects two of the musicians
|
||||
results = Search.musician_filter({page: 3, per_page: 3, score_limit: Search::TEST_SCORE})
|
||||
results.search_type.should == :musicians_filter
|
||||
results.results.count.should == 0
|
||||
end
|
||||
|
||||
it "sorts musicians by followers" do
|
||||
# establish sorting order
|
||||
|
||||
# @user4
|
||||
f1 = Follow.new
|
||||
f1.user = @user2
|
||||
f1.followable = @user4
|
||||
f1.save
|
||||
|
||||
f2 = Follow.new
|
||||
f2.user = @user3
|
||||
f2.followable = @user4
|
||||
f2.save
|
||||
|
||||
f3 = Follow.new
|
||||
f3.user = @user4
|
||||
f3.followable = @user4
|
||||
f3.save
|
||||
|
||||
# @user3
|
||||
f4 = Follow.new
|
||||
f4.user = @user3
|
||||
f4.followable = @user3
|
||||
f4.save
|
||||
|
||||
f5 = Follow.new
|
||||
f5.user = @user4
|
||||
f5.followable = @user3
|
||||
f5.save
|
||||
|
||||
# @user2
|
||||
f6 = Follow.new
|
||||
f6.user = @user1
|
||||
f6.followable = @user2
|
||||
f6.save
|
||||
|
||||
# @user4.followers.concat([@user2, @user3, @user4])
|
||||
# @user3.followers.concat([@user3, @user4])
|
||||
# @user2.followers.concat([@user1])
|
||||
expect(@user4.followers.count).to be 3
|
||||
expect(Follow.count).to be 6
|
||||
|
||||
# refresh the order to ensure it works right
|
||||
f1 = Follow.new
|
||||
f1.user = @user3
|
||||
f1.followable = @user2
|
||||
f1.save
|
||||
|
||||
f2 = Follow.new
|
||||
f2.user = @user4
|
||||
f2.followable = @user2
|
||||
f2.save
|
||||
|
||||
f3 = Follow.new
|
||||
f3.user = @user2
|
||||
f3.followable = @user2
|
||||
f3.save
|
||||
|
||||
# @user2.followers.concat([@user3, @user4, @user2])
|
||||
results = Search.musician_filter({:per_page => @musicians.size, score_limit: Search::TEST_SCORE, orderby: 'followed'}, @user3)
|
||||
expect(results.results[0].id).to eq(@user2.id)
|
||||
|
||||
# check the follower count for given entry
|
||||
expect(results.results[0].search_follow_count.to_i).not_to eq(0)
|
||||
# check the follow relationship between current_user and result
|
||||
expect(results.is_follower?(@user2)).to be true
|
||||
end
|
||||
|
||||
it 'paginates properly' do
|
||||
# make sure pagination works right
|
||||
params = {:per_page => 2, :page => 1, score_limit: Search::TEST_SCORE}
|
||||
results = Search.musician_filter(params)
|
||||
expect(results.results.count).to be 2
|
||||
end
|
||||
|
||||
it "sorts by latency" do
|
||||
search.update_json_value(MusicianSearch::KEY_SORT_ORDER, MusicianSearch::SORT_VALS[0])
|
||||
results = search.do_search
|
||||
expect(results[0].id).to eq(@user1.id)
|
||||
expect(results[1].id).to eq(@user2.id)
|
||||
expect(results[2].id).to eq(@user3.id)
|
||||
expect(results[3].id).to eq(@user4.id)
|
||||
end
|
||||
|
||||
def make_recording(usr)
|
||||
connection = FactoryGirl.create(:connection, :user => usr, locidispid: usr.last_jam_locidispid)
|
||||
instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
|
||||
track = FactoryGirl.create(:track, :connection => connection, :instrument => instrument)
|
||||
music_session = FactoryGirl.create(:active_music_session, :creator => usr, :musician_access => true)
|
||||
# music_session.connections << connection
|
||||
# music_session.save
|
||||
connection.join_the_session(music_session, true, nil, usr, 10)
|
||||
recording = Recording.start(music_session, usr)
|
||||
recording.stop
|
||||
recording.reload
|
||||
genre = FactoryGirl.create(:genre)
|
||||
recording.claim(usr, "name", "description", genre, true)
|
||||
recording.reload
|
||||
recording
|
||||
end
|
||||
|
||||
def make_session(usr)
|
||||
connection = FactoryGirl.create(:connection, :user => usr, locidispid: usr.last_jam_locidispid)
|
||||
music_session = FactoryGirl.create(:active_music_session, :creator => usr, :musician_access => true)
|
||||
# music_session.connections << connection
|
||||
# music_session.save
|
||||
connection.join_the_session(music_session, true, nil, usr, 10)
|
||||
end
|
||||
|
||||
context 'musician stat counters' do
|
||||
|
||||
it "displays musicians top followings" do
|
||||
f1 = Follow.new
|
||||
f1.user = @user4
|
||||
f1.followable = @user4
|
||||
f1.save
|
||||
|
||||
f2 = Follow.new
|
||||
f2.user = @user4
|
||||
f2.followable = @user3
|
||||
f2.save
|
||||
|
||||
f3 = Follow.new
|
||||
f3.user = @user4
|
||||
f3.followable = @user2
|
||||
f3.save
|
||||
|
||||
# @user4.followers.concat([@user4])
|
||||
# @user3.followers.concat([@user4])
|
||||
# @user2.followers.concat([@user4])
|
||||
expect(@user4.top_followings.count).to eq 3
|
||||
expect(@user4.top_followings.map(&:id)).to match_array((@musicians - [@user1, @user5, @user6]).map(&:id))
|
||||
end
|
||||
|
||||
it "friends stat shows friend count" do
|
||||
# create friendship record
|
||||
Friendship.save(@user1.id, @user2.id)
|
||||
# search on user2
|
||||
results = Search.musician_filter({score_limit: Search::TEST_SCORE}, @user2)
|
||||
friend = results.results.detect { |mm| mm.id == @user1.id }
|
||||
expect(friend).to_not be_nil
|
||||
expect(results.friend_count(friend)).to be 1
|
||||
@user1.reload
|
||||
expect(friend.friends?(@user2)).to be true
|
||||
expect(results.is_friend?(@user1)).to be true
|
||||
end
|
||||
|
||||
it "recording stat shows recording count" do
|
||||
Recording.delete_all
|
||||
|
||||
recording = make_recording(@user1)
|
||||
expect(recording.users.length).to be 1
|
||||
expect(recording.users.first).to eq(@user1)
|
||||
@user1.reload
|
||||
expect(@user1.recordings.length).to be 1
|
||||
expect(@user1.recordings.first).to eq(recording)
|
||||
expect(recording.claimed_recordings.length).to be 1
|
||||
expect(@user1.recordings.detect { |rr| rr == recording }).to_not be_nil
|
||||
|
||||
results = Search.musician_filter({score_limit: Search::TEST_SCORE}, @user1)
|
||||
# puts "====================== results #{results.inspect}"
|
||||
uu = results.results.detect { |mm| mm.id == @user1.id }
|
||||
expect(uu).to_not be_nil
|
||||
|
||||
expect(results.record_count(uu)).to be 1
|
||||
expect(results.session_count(uu)).to be 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'musician sorting' do
|
||||
|
||||
it "by plays" do
|
||||
Recording.delete_all
|
||||
|
||||
make_recording(@user1)
|
||||
# order results by num recordings
|
||||
results = Search.musician_filter({orderby: 'plays', score_limit: Search::TEST_SCORE}, @user2)
|
||||
# puts "========= results #{results.inspect}"
|
||||
expect(results.results.length).to eq(2)
|
||||
expect(results.results[0].id).to eq(@user1.id)
|
||||
expect(results.results[1].id).to eq(@user3.id)
|
||||
|
||||
# add more data and make sure order still correct
|
||||
make_recording(@user3)
|
||||
make_recording(@user3)
|
||||
results = Search.musician_filter({:orderby => 'plays', score_limit: Search::TEST_SCORE}, @user2)
|
||||
expect(results.results.length).to eq(2)
|
||||
expect(results.results[0].id).to eq(@user3.id)
|
||||
expect(results.results[1].id).to eq(@user1.id)
|
||||
end
|
||||
|
||||
it "by now playing" do
|
||||
pending "these tests worked, so leaving them in, but we don't currently have 'Now Playing' in the find musicians screen"
|
||||
# should get 1 result with 1 active session
|
||||
make_session(@user1)
|
||||
results = Search.musician_filter({:orderby => 'playing', score_limit: Search::TEST_SCORE}, @user2)
|
||||
expect(results.results.count).to be 1
|
||||
expect(results.results.first.id).to eq(@user1.id)
|
||||
|
||||
# should get 2 results with 2 active sessions
|
||||
# sort order should be created_at DESC
|
||||
make_session(@user3)
|
||||
results = Search.musician_filter({:orderby => 'playing', score_limit: Search::TEST_SCORE}, @user2)
|
||||
expect(results.results.count).to be 2
|
||||
expect(results.results[0].id).to eq(@user3.id)
|
||||
expect(results.results[1].id).to eq(@user1.id)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'filter settings' do
|
||||
it "searches musicians for an instrument" do
|
||||
minst = FactoryGirl.create(:musician_instrument, {
|
||||
:user => @user1,
|
||||
:instrument => Instrument.find('tuba')})
|
||||
@user1.musician_instruments << minst
|
||||
@user1.reload
|
||||
ii = @user1.instruments.detect { |inst| inst.id == 'tuba' }
|
||||
expect(ii).to_not be_nil
|
||||
results = Search.musician_filter({:instrument => ii.id, score_limit: Search::TEST_SCORE}, @user2)
|
||||
results.results.each do |rr|
|
||||
expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id)
|
||||
end
|
||||
expect(results.results.count).to be 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'new users' do
|
||||
|
||||
it "find three for user1" do
|
||||
# user2..4 are scored against user1
|
||||
ms = Search.new_musicians(@user1, Time.now - 1.week)
|
||||
ms.should_not be_nil
|
||||
ms.length.should == 3
|
||||
ms.should eq [@user2, @user3, @user4]
|
||||
end
|
||||
|
||||
it "find two for user2" do
|
||||
# user1,3,4 are scored against user1, but user4 is bad
|
||||
ms = Search.new_musicians(@user2, Time.now - 1.week)
|
||||
ms.should_not be_nil
|
||||
ms.length.should == 2
|
||||
ms.should eq [@user3, @user1]
|
||||
end
|
||||
|
||||
it "find two for user3" do
|
||||
# user1..2 are scored against user3
|
||||
ms = Search.new_musicians(@user3, Time.now - 1.week)
|
||||
ms.should_not be_nil
|
||||
ms.length.should == 2
|
||||
ms.should eq [@user2, @user1]
|
||||
end
|
||||
|
||||
it "find one for user4" do
|
||||
# user1..2 are scored against user4, but user2 is bad
|
||||
ms = Search.new_musicians(@user4, Time.now - 1.week)
|
||||
ms.should_not be_nil
|
||||
ms.length.should == 1
|
||||
ms.should eq [@user1]
|
||||
end
|
||||
|
||||
it "find none for user5" do
|
||||
# user1..4 are not scored against user5
|
||||
ms = Search.new_musicians(@user5, Time.now - 1.week)
|
||||
ms.should_not be_nil
|
||||
ms.length.should == 0
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
describe "produces accurate query description" do
|
||||
before(:all) do
|
||||
User.delete_all
|
||||
end
|
||||
|
||||
it 'has default description' do
|
||||
expect(search.description).to match(/^Click search button to look for musicians/)
|
||||
end
|
||||
|
||||
it 'has correct sort order description' do
|
||||
search.update_json_value(MusicianSearch::KEY_SORT_ORDER, MusicianSearch::SORT_VALS[1])
|
||||
str = MusicianSearch::SORT_ORDERS[search.json_value(MusicianSearch::KEY_SORT_ORDER)]
|
||||
expect(search.description).to match(/^Current Search: Sort = #{str}$/)
|
||||
end
|
||||
|
||||
it 'has correct description for single-valued selections' do
|
||||
selections = [{
|
||||
key: MusicianSearch::KEY_INTERESTS,
|
||||
value: MusicianSearch::INTEREST_VALS[1],
|
||||
lookup: MusicianSearch::INTERESTS,
|
||||
description: 'Interest'
|
||||
},
|
||||
{
|
||||
key: MusicianSearch::KEY_SKILL,
|
||||
value: MusicianSearch::SKILL_VALS[1],
|
||||
lookup: MusicianSearch::SKILL_LEVELS,
|
||||
description: 'Skill'
|
||||
},
|
||||
{
|
||||
key: MusicianSearch::KEY_STUDIOS,
|
||||
value: MusicianSearch::STUDIO_COUNTS[1],
|
||||
lookup: MusicianSearch::STUDIOS_LABELS,
|
||||
description: 'Studio Sessions'
|
||||
},
|
||||
{
|
||||
key: MusicianSearch::KEY_GIGS,
|
||||
value: MusicianSearch::GIG_COUNTS[1],
|
||||
lookup: MusicianSearch::GIG_LABELS,
|
||||
description: 'Concert Gigs'
|
||||
}]
|
||||
selections.each do |hash|
|
||||
search.update_json_value(hash[:key], hash[:value])
|
||||
json_val = search.json_value(hash[:key])
|
||||
expect(search.description).to match(/; #{hash[:description]} = #{hash[:lookup][json_val]}/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'has correct description for genres' do
|
||||
search.update_json_value(MusicianSearch::KEY_GENRES, [Genre.first.id, Genre.last.id])
|
||||
expect(search.description).to match(/; Genres = #{Genre.first.description}, #{Genre.last.description}/)
|
||||
end
|
||||
|
||||
it 'has correct description for ages' do
|
||||
search.update_json_value(MusicianSearch::KEY_AGES, [MusicianSearch::AGE_COUNTS[0],MusicianSearch::AGE_COUNTS[1]])
|
||||
expect(search.description).to match(/; Ages = #{MusicianSearch::AGES[MusicianSearch::AGE_COUNTS[0]]}, #{MusicianSearch::AGES[MusicianSearch::AGE_COUNTS[1]]}/)
|
||||
end
|
||||
|
||||
it 'has correct description for instruments' do
|
||||
instrs = Instrument.limit(2).order(:description)
|
||||
instjson = [{ instrument_id: instrs[0].id, proficiency_level: 2 },
|
||||
{ instrument_id: instrs[1].id, proficiency_level: 1 }
|
||||
]
|
||||
search.update_json_value(MusicianSearch::KEY_INSTRUMENTS, instjson)
|
||||
instr_descrip = "#{instrs[0].description} (#{MusicianSearch::INSTRUMENT_PROFICIENCY[2]}), #{instrs[1].description} (#{MusicianSearch::INSTRUMENT_PROFICIENCY[1]})"
|
||||
expect(search.description).to match(/; Instruments = #{Regexp.escape(instr_descrip)}/)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,173 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe OnlinePresence do
|
||||
|
||||
shared_examples_for :online_presence_specs do
|
||||
describe "index" do
|
||||
|
||||
before(:all) do
|
||||
OnlinePresence.delete_all
|
||||
|
||||
player1_presence1 = OnlinePresence.new({:player_id => player1.id, :username => "myonlineusername", :service_type => "facebook"})
|
||||
player1_presence1.save!
|
||||
|
||||
player1_presence2 = OnlinePresence.new({:player_id => player1.id, :username => "myonlineusername", :service_type => "twitter"})
|
||||
player1_presence2.save!
|
||||
|
||||
player2_presence1 = OnlinePresence.new({:player_id => player2.id, :username => "myonlineusername", :service_type => "soundcloud"})
|
||||
player2_presence1.save!
|
||||
end
|
||||
|
||||
context "when request is valid" do
|
||||
it "should return all records for user" do
|
||||
presence = OnlinePresence.index({:id => player1.id})
|
||||
presence.count.should == 2
|
||||
|
||||
presence = OnlinePresence.index({:id => player2.id})
|
||||
presence.count.should == 1
|
||||
end
|
||||
end
|
||||
|
||||
context "when request is invalid" do
|
||||
it "should raise error when options are missing" do
|
||||
lambda{OnlinePresence.index}.should raise_error(StateError)
|
||||
end
|
||||
|
||||
it "should raise error when user id is missing" do
|
||||
lambda{OnlinePresence.index({:id => ""})}.should raise_error(StateError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "create" do
|
||||
|
||||
before(:all) do
|
||||
OnlinePresence.delete_all
|
||||
end
|
||||
|
||||
context "when request is valid" do
|
||||
it "should save successfully" do
|
||||
OnlinePresence.create(player1, {:player_id => player1.id, :service_type => "soundcloud", :username => "soundcloudplayer1"})
|
||||
|
||||
# make sure we can save a second OnlinePresence for same user and type
|
||||
OnlinePresence.create(player1, {:player_id => player1.id, :service_type => "soundcloud", :username => "soundcloudplayer2"})
|
||||
|
||||
OnlinePresence.index({:id => player1.id}).count.should == 2
|
||||
end
|
||||
end
|
||||
|
||||
context "when request is not valid" do
|
||||
it "should raise JamPermissionError if requester id does not match id in request" do
|
||||
lambda{OnlinePresence.create(player1, {:player_id => player2.id, :service_type => "soundcloud", :username => "soundcloudplayer2"})}.should raise_error(JamPermissionError)
|
||||
end
|
||||
|
||||
it "should raise error if service type is missing" do
|
||||
lambda{OnlinePresence.create(player1, {:player_id => player1.id, :username => "soundcloudplayer2"})}.should raise_error(StateError)
|
||||
end
|
||||
|
||||
it "should raise error if username is missing" do
|
||||
lambda{OnlinePresence.create(player1, {:player_id => player1.id, :service_type => "soundcloud"})}.should raise_error(StateError)
|
||||
end
|
||||
|
||||
it "should not allow duplicates of the same username / service type combination" do
|
||||
OnlinePresence.create(player1, {:player_id => player1.id, :service_type => "soundcloud", :username => "soundcloudplayer1"})
|
||||
OnlinePresence.index({:id => player1.id}).count.should == 1
|
||||
|
||||
lambda{OnlinePresence.create(player1, {:player_id => player1.id, :service_type => "soundcloud", :username => "soundcloudplayer1"})}.should raise_error(ConflictError)
|
||||
OnlinePresence.index({:id => player1.id}).count.should == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "update" do
|
||||
|
||||
before(:all) do
|
||||
OnlinePresence.delete_all
|
||||
@online_presence = OnlinePresence.new(:player_id => player1.id, :service_type => "soundcloud", :username => "soundcloudplayer1")
|
||||
@online_presence.save!
|
||||
end
|
||||
|
||||
context "when request is valid" do
|
||||
it "should save successfully" do
|
||||
|
||||
up_list = OnlinePresence.index({:id => player1.id})
|
||||
up_list.count.should == 1
|
||||
up_list.first.service_type.should == "soundcloud"
|
||||
up_list.first.username.should == "soundcloudplayer1"
|
||||
|
||||
OnlinePresence.update(player1, {:id => @online_presence.id, :player_id => player1.id, :service_type => "soundcloud", :username => "soundcloudplayer2"})
|
||||
|
||||
up_list = OnlinePresence.index({:id => player1.id})
|
||||
up_list.count.should == 1
|
||||
up_list.first.service_type.should == "soundcloud"
|
||||
up_list.first.username.should == "soundcloudplayer2"
|
||||
end
|
||||
end
|
||||
|
||||
context "when request is not valid" do
|
||||
it "should raise JamPermissionError if requester id does not match id in request" do
|
||||
lambda{OnlinePresence.update(player1, {:player_id => player2.id, :id => @online_presence.id, :service_type => "soundcloud", :username => "soundcloudplayer2"})}.should raise_error(JamPermissionError)
|
||||
end
|
||||
|
||||
it "should raise error if type is missing" do
|
||||
lambda{OnlinePresence.update(player1, {:player_id => player1.id, :id => @online_presence.id, :username => "soundcloudplayer2"})}.should raise_error(StateError)
|
||||
end
|
||||
|
||||
it "should raise error if username is missing" do
|
||||
lambda{OnlinePresence.update(player1, {:player_id => player1.id, :id => @online_presence.id, :service_type => "soundcloud"})}.should raise_error(StateError)
|
||||
end
|
||||
|
||||
it "should raise error if player presence id is missing" do
|
||||
lambda{OnlinePresence.update(player1, {:player_id => player1.id, :username => "soundcloudplayer2", :service_type => "soundcloud"})}.should raise_error(StateError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "destroy" do
|
||||
|
||||
before(:all) do
|
||||
OnlinePresence.delete_all
|
||||
@online_presence = OnlinePresence.new(:player_id => player1.id, :service_type => "soundcloud", :username => "soundcloudplayer1")
|
||||
@online_presence.save!
|
||||
end
|
||||
|
||||
context "when request is valid" do
|
||||
it "should destroy successfully" do
|
||||
up_list = OnlinePresence.index({:id => player1.id})
|
||||
up_list.count.should == 1
|
||||
up_list.first.service_type.should == "soundcloud"
|
||||
up_list.first.username.should == "soundcloudplayer1"
|
||||
|
||||
OnlinePresence.delete(player1, {:player_id => player1.id, :id => @online_presence.id})
|
||||
|
||||
up_list = OnlinePresence.index({:id => player1.id})
|
||||
up_list.count.should == 0
|
||||
end
|
||||
end
|
||||
|
||||
context "when request is not valid" do
|
||||
it "should raise JamPermissionError if requester id does not match id in request" do
|
||||
lambda{OnlinePresence.delete(player2, {:player_id => player1.id, :id => @online_presence.id})}.should raise_error(JamPermissionError)
|
||||
end
|
||||
|
||||
it "should raise error if player presence id is missing" do
|
||||
lambda{OnlinePresence.delete(player1, {:player_id => player1.id})}.should raise_error(StateError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end # shared
|
||||
|
||||
describe "with a user" do
|
||||
it_should_behave_like :online_presence_specs do
|
||||
let(:player1) { FactoryGirl.create(:user) }
|
||||
let(:player2) { FactoryGirl.create(:user) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a band" do
|
||||
it_should_behave_like :online_presence_specs do
|
||||
let(:player1) { FactoryGirl.create(:band) }
|
||||
let(:player2) { FactoryGirl.create(:band) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe PerformanceSample do
|
||||
|
||||
shared_examples_for :performance_sample_specs do
|
||||
let(:claimed_recording) { FactoryGirl.create(:claimed_recording) }
|
||||
|
||||
describe "index" do
|
||||
|
||||
before(:all) do
|
||||
PerformanceSample.delete_all
|
||||
|
||||
@player1_sample1 = PerformanceSample.new(:player_id => player1.id, :service_type => "jamkazam", :claimed_recording_id => claimed_recording.id)
|
||||
@player1_sample1.save!
|
||||
|
||||
@player1_sample2 = PerformanceSample.new(:player_id => player1.id, :service_type => "youtube", :service_id => "12345")
|
||||
@player1_sample2.save!
|
||||
|
||||
@player2_sample1 = PerformanceSample.new(:player_id => player2.id, :service_type => "soundcloud", :service_id => "67890")
|
||||
@player2_sample1.save!
|
||||
end
|
||||
|
||||
context "when request is valid" do
|
||||
it "should return all records for user" do
|
||||
sample = PerformanceSample.index({:id => player1.id})
|
||||
sample.count.should == 2
|
||||
|
||||
sample = PerformanceSample.index({:id => player2.id})
|
||||
sample.count.should == 1
|
||||
end
|
||||
end
|
||||
|
||||
context "when request is invalid" do
|
||||
it "should raise error when options are missing" do
|
||||
lambda{PerformanceSample.index}.should raise_error(JamArgumentError)
|
||||
end
|
||||
|
||||
it "should raise error when user id is missing" do
|
||||
lambda{PerformanceSample.index({:id => ""})}.should raise_error(JamArgumentError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "create" do
|
||||
|
||||
before(:all) do
|
||||
PerformanceSample.delete_all
|
||||
end
|
||||
|
||||
context "when request is valid" do
|
||||
it "should save successfully" do
|
||||
PerformanceSample.create(player1, {:player_id => player1.id, :service_type => "youtube", :service_id => "12345"})
|
||||
|
||||
# make sure we can save a second PerformanceSample for same user and type
|
||||
PerformanceSample.create(player1, {:player_id => player1.id, :service_type => "youtube", :service_id => "67890"})
|
||||
end
|
||||
end
|
||||
|
||||
context "when request is not valid" do
|
||||
it "should raise JamPermissionError if requester id does not match id in request" do
|
||||
lambda{PerformanceSample.create(player1, {:player_id => player2.id, :service_type => "soundcloud", :service_id => "12345"})}.should raise_error(JamPermissionError)
|
||||
end
|
||||
|
||||
it "should raise error if service type is missing" do
|
||||
lambda{PerformanceSample.create(player1, {:player_id => player1.id, :service_id => "12345"})}.should raise_error(StateError)
|
||||
end
|
||||
|
||||
it "should raise error if service id is missing for non-JamKazam sample" do
|
||||
lambda{PerformanceSample.create(player1, {:player_id => player1.id, :service_type => "youtube"})}.should raise_error(StateError)
|
||||
end
|
||||
|
||||
it "should raise error if recording id is missing for JamKazam sample" do
|
||||
lambda{PerformanceSample.create(player1, {:player_id => player1.id, :service_type => "jamkazam"})}.should raise_error(StateError)
|
||||
end
|
||||
|
||||
it "should not allow duplicate type/service id combination for non-JamKazam sample" do
|
||||
PerformanceSample.create(player1, {:player_id => player1.id, :service_type => "youtube", :service_id => "12345"})
|
||||
lambda{PerformanceSample.create(player1, {:player_id => player1.id, :service_type => "youtube", :service_id => "12345"})}.should raise_error(ConflictError)
|
||||
end
|
||||
|
||||
it "should not allow duplicate type/recording id combination for JamKazam sample" do
|
||||
PerformanceSample.create(player1, {:player_id => player1.id, :service_type => "jamkazam", :claimed_recording_id => claimed_recording.id})
|
||||
lambda{PerformanceSample.create(player1, {:player_id => player1.id, :service_type => "jamkazam", :claimed_recording_id => claimed_recording.id})}.should raise_error(ConflictError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "destroy" do
|
||||
|
||||
before(:all) do
|
||||
PerformanceSample.delete_all
|
||||
@user_sample = PerformanceSample.new(:player_id => player1.id, :service_type => "soundcloud", :service_id => "12345")
|
||||
@user_sample.save!
|
||||
end
|
||||
|
||||
context "when request is valid" do
|
||||
it "should destroy successfully" do
|
||||
ps_list = PerformanceSample.index({:id => player1.id})
|
||||
ps_list.count.should == 1
|
||||
ps_list.first.service_type.should == "soundcloud"
|
||||
ps_list.first.service_id.should == "12345"
|
||||
|
||||
PerformanceSample.delete(player1, {:player_id => player1.id, :id => @user_sample.id})
|
||||
|
||||
ps_list = PerformanceSample.index({:id => player1.id})
|
||||
ps_list.count.should == 0
|
||||
end
|
||||
end
|
||||
|
||||
context "when request is not valid" do
|
||||
it "should raise JamPermissionError if requester id does not match id in request" do
|
||||
lambda{PerformanceSample.delete(player2, {:player_id => player1.id, :id => @user_sample.id})}.should raise_error(JamPermissionError)
|
||||
end
|
||||
|
||||
it "should raise error if user sample id is missing" do
|
||||
lambda{PerformanceSample.delete(player1, {:player_id => player1.id})}.should raise_error(StateError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a user" do
|
||||
it_should_behave_like :performance_sample_specs do
|
||||
let(:player1) { FactoryGirl.create(:user) }
|
||||
let(:player2) { FactoryGirl.create(:user) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a band" do
|
||||
it_should_behave_like :performance_sample_specs do
|
||||
let(:player1) { FactoryGirl.create(:band) }
|
||||
let(:player2) { FactoryGirl.create(:band) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -9,7 +9,7 @@ describe User do
|
|||
User.delete_all
|
||||
@user = User.new(first_name: "Example", last_name: "User", email: "user@example.com",
|
||||
password: "foobar", password_confirmation: "foobar", city: "Apex", state: "NC", country: "US", terms_of_service: true, musician: true)
|
||||
@user.musician_instruments << FactoryGirl.build(:musician_instrument, user: @user)
|
||||
@user.musician_instruments << FactoryGirl.build(:musician_instrument, player: @user)
|
||||
@recurly = RecurlyClient.new
|
||||
end
|
||||
|
||||
|
|
@ -701,13 +701,16 @@ describe User do
|
|||
|
||||
describe "age" do
|
||||
let(:user) {FactoryGirl.create(:user)}
|
||||
|
||||
|
||||
it "should calculate age based on birth_date" do
|
||||
user.birth_date = Time.now - 10.years
|
||||
user.age.should == 10
|
||||
|
||||
user.birth_date = Time.now - 10.years + 3.months
|
||||
user.age.should == 9
|
||||
|
||||
user.birth_date = nil
|
||||
user.age.should == ""
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -98,13 +98,13 @@ describe "RenderMailers", :slow => true do
|
|||
BatchMailer.deliveries.clear
|
||||
scheduled_batch.reset!
|
||||
|
||||
drummer.musician_instruments << FactoryGirl.build(:musician_instrument, user: drummer, instrument: drums, proficiency_level: 2)
|
||||
drummer.musician_instruments << FactoryGirl.build(:musician_instrument, user: drummer, instrument: guitar, proficiency_level: 2)
|
||||
drummer.musician_instruments << FactoryGirl.build(:musician_instrument, player: drummer, instrument: drums, proficiency_level: 2)
|
||||
drummer.musician_instruments << FactoryGirl.build(:musician_instrument, player: drummer, instrument: guitar, proficiency_level: 2)
|
||||
|
||||
guitarist.musician_instruments << FactoryGirl.build(:musician_instrument, user: guitarist, instrument: guitar, proficiency_level: 2)
|
||||
guitarist.musician_instruments << FactoryGirl.build(:musician_instrument, user: guitarist, instrument: bass, proficiency_level: 2)
|
||||
guitarist.musician_instruments << FactoryGirl.build(:musician_instrument, player: guitarist, instrument: guitar, proficiency_level: 2)
|
||||
guitarist.musician_instruments << FactoryGirl.build(:musician_instrument, player: guitarist, instrument: bass, proficiency_level: 2)
|
||||
|
||||
vocalist.musician_instruments << FactoryGirl.build(:musician_instrument, user: vocalist, instrument: vocals, proficiency_level: 2)
|
||||
vocalist.musician_instruments << FactoryGirl.build(:musician_instrument, player: vocalist, instrument: vocals, proficiency_level: 2)
|
||||
|
||||
FactoryGirl.create(:rsvp_slot, :instrument => drums, :music_session => session1)
|
||||
FactoryGirl.create(:rsvp_slot, :instrument => guitar, :music_session => session1)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ gem 'sendgrid', '1.2.0'
|
|||
gem 'filepicker-rails', '0.1.0'
|
||||
gem 'aws-sdk', '~> 1'
|
||||
gem 'aasm', '3.0.16'
|
||||
gem 'carmen'
|
||||
gem 'carrierwave', '0.9.0'
|
||||
gem 'carrierwave_direct'
|
||||
gem 'fog'
|
||||
|
|
@ -106,8 +107,10 @@ group :development, :test do
|
|||
gem 'execjs', '1.4.0'
|
||||
gem 'factory_girl_rails', '4.1.0' # in dev because in use by rake task
|
||||
gem 'database_cleaner', '1.3.0' #in dev because in use by rake task
|
||||
# gem 'teaspoon'
|
||||
# gem 'teaspoon-jasmine'
|
||||
|
||||
# gem 'teaspoon'
|
||||
# gem 'teaspoon-jasmine'
|
||||
# gem 'puma'
|
||||
end
|
||||
group :unix do
|
||||
gem 'therubyracer' #, '0.11.0beta8'
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 828 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
|
@ -59,11 +59,21 @@
|
|||
// wire up main panel clicks
|
||||
$('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-upload', function(evt) { evt.stopPropagation(); handleFilePick(); return false; } );
|
||||
$('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-delete', function(evt) { evt.stopPropagation(); handleDeleteAvatar(); return false; } );
|
||||
$('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-cancel', function(evt) { evt.stopPropagation(); navToEditProfile(); return false; } );
|
||||
$('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-submit', function(evt) { evt.stopPropagation(); handleUpdateAvatar(); return false; } );
|
||||
$('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-cancel', function(evt) { evt.stopPropagation(); navToEditProfile(); return false; } );
|
||||
enableSubmits()
|
||||
//$('#account-profile-avatar-content-scroller').on('change', 'input[type=filepicker-dragdrop]', function(evt) { evt.stopPropagation(); afterImageUpload(evt.originalEvent.fpfile); return false; } );
|
||||
}
|
||||
|
||||
function enableSubmits() {
|
||||
$('#account-profile-avatar-content-scroller').on('click', '#account-edit-avatar-submit', function(evt) { evt.stopPropagation(); handleUpdateAvatar(); return false; } );
|
||||
$("#account-edit-avatar-submit").removeClass("disabled")
|
||||
}
|
||||
|
||||
function disableSubmits() {
|
||||
$("#account-edit-avatar-submit").addClass("disabled")
|
||||
$("#account-edit-avatar-submit").off("click")
|
||||
}
|
||||
|
||||
function handleDeleteAvatar() {
|
||||
|
||||
if(self.updatingAvatar) {
|
||||
|
|
@ -277,7 +287,7 @@
|
|||
}
|
||||
|
||||
function handleUpdateAvatar(event) {
|
||||
|
||||
disableSubmits()
|
||||
if(self.updatingAvatar) {
|
||||
// protect against concurrent update attempts
|
||||
return;
|
||||
|
|
@ -373,10 +383,11 @@
|
|||
},
|
||||
null,
|
||||
true);
|
||||
}
|
||||
}
|
||||
enableSubmits()
|
||||
}
|
||||
|
||||
function updateAvatarSuccess(response) {
|
||||
function updateAvatarSuccess(response) {
|
||||
$.cookie('original_fpfile', null);
|
||||
|
||||
self.userDetail = response;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,236 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.AccountProfileExperience = function(app) {
|
||||
var $document = $(document);
|
||||
var logger = context.JK.logger;
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
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 $instrumentSelector = $screen.find('.instrument_selector');
|
||||
var $userGenres = $screen.find('#user-genres');
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
resetForm();
|
||||
renderExperience();
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
$screen.find('form .error-text').remove();
|
||||
$screen.find('form .error').removeClass("error");
|
||||
}
|
||||
|
||||
function populateAccountProfile(userDetail, instruments) {
|
||||
|
||||
loadGenres(profileUtils.profileGenres(userDetail.genres));
|
||||
|
||||
$instrumentSelector.empty();
|
||||
$.each(instruments, function(index, instrument) {
|
||||
var template = context.JK.fillTemplate($('#account-profile-instrument').html(), {
|
||||
checked : isUserInstrument(instrument, userDetail.instruments) ? "checked=\"checked\"" :"",
|
||||
description : instrument.description,
|
||||
id : instrument.id
|
||||
});
|
||||
$instrumentSelector.append(template);
|
||||
});
|
||||
|
||||
// and fill in the proficiency for the instruments that the user can play
|
||||
if(userDetail.instruments) {
|
||||
$.each(userDetail.instruments, function(index, userInstrument) {
|
||||
$('tr[data-instrument-id="' + userInstrument.instrument_id + '"] select.proficiency_selector', $screen).val(userInstrument.proficiency_level);
|
||||
});
|
||||
}
|
||||
|
||||
$screen.find('select[name=skill_level]').val(userDetail.skill_level);
|
||||
$screen.find('select[name=concert_count]').val(userDetail.concert_count);
|
||||
$screen.find('select[name=studio_session_count]').val(userDetail.studio_session_count);
|
||||
|
||||
context.JK.dropdown($('select', $screen));
|
||||
}
|
||||
|
||||
function isUserInstrument(instrument, userInstruments) {
|
||||
var isUserInstrument = false;
|
||||
if(!userInstruments) return false;
|
||||
|
||||
$.each(userInstruments, function(index, userInstrument) {
|
||||
if(instrument.id == userInstrument.instrument_id) {
|
||||
isUserInstrument = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return isUserInstrument;
|
||||
}
|
||||
|
||||
function loadGenres(selectedGenres) {
|
||||
$userGenres.empty();
|
||||
|
||||
rest.getGenres().done(function (genres) {
|
||||
$.each(genres, function (index, genre) {
|
||||
var genreTemplate = $('#template-user-setup-genres').html();
|
||||
var selected = '';
|
||||
if (selectedGenres) {
|
||||
var genreMatch = $.grep(selectedGenres, function (n, i) {
|
||||
return n.genre_id === genre.id;
|
||||
});
|
||||
if (genreMatch.length > 0) {
|
||||
selected = "checked";
|
||||
}
|
||||
}
|
||||
var genreHtml = context.JK.fillTemplate(genreTemplate, {
|
||||
id: genre.id,
|
||||
description: genre.description,
|
||||
checked: selected
|
||||
});
|
||||
$userGenres.append(genreHtml);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function resetGenres() {
|
||||
$('input[type=checkbox]:checked', $userGenres).each(function (i) {
|
||||
$(this).removeAttr("checked");
|
||||
});
|
||||
var $tdGenres = $("#tdBandGenres");
|
||||
}
|
||||
|
||||
function getSelectedGenres() {
|
||||
var genres = [];
|
||||
$('input[type=checkbox]:checked', $userGenres).each(function (i) {
|
||||
var genre = $(this).val();
|
||||
genres.push(genre);
|
||||
});
|
||||
return genres;
|
||||
}
|
||||
|
||||
function events() {
|
||||
$btnCancel.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/profile/' + context.JK.currentUserId);
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnBack.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/account/profile/');
|
||||
return false;
|
||||
});
|
||||
|
||||
enableSubmits()
|
||||
}
|
||||
|
||||
function enableSubmits() {
|
||||
$btnSubmit.on("click", function(evt) {
|
||||
evt.stopPropagation();
|
||||
handleUpdateProfile();
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnSubmit.removeClass("disabled")
|
||||
}
|
||||
|
||||
function disableSubmits() {
|
||||
$btnSubmit.addClass("disabled")
|
||||
$btnSubmit.off("click")
|
||||
}
|
||||
|
||||
function renderExperience() {
|
||||
$.when(api.getUserProfile(), api.getInstruments())
|
||||
.done(function(userDetailResponse, instrumentsResponse) {
|
||||
var userDetail = userDetailResponse[0];
|
||||
populateAccountProfile(userDetail, instrumentsResponse[0]);
|
||||
});
|
||||
|
||||
context.JK.dropdown($('select'));
|
||||
}
|
||||
|
||||
function navigateTo(targetLocation) {
|
||||
resetForm();
|
||||
context.location = targetLocation;
|
||||
}
|
||||
|
||||
function handleUpdateProfile() {
|
||||
disableSubmits()
|
||||
resetForm();
|
||||
|
||||
var instruments = getSelectedInstruments();
|
||||
var genres = getSelectedGenres();
|
||||
|
||||
api.updateUser({
|
||||
instruments: instruments,
|
||||
genres: genres,
|
||||
skill_level: $screen.find('select[name=skill_level]').val(),
|
||||
concert_count: $screen.find('select[name=concert_count]').val(),
|
||||
studio_session_count: $screen.find('select[name=studio_session_count]').val()
|
||||
})
|
||||
.done(postUpdateProfileSuccess)
|
||||
.fail(postUpdateProfileFailure)
|
||||
.always(enableSubmits)
|
||||
}
|
||||
|
||||
function postUpdateProfileSuccess(response) {
|
||||
$document.triggerHandler(EVENTS.USER_UPDATED, response);
|
||||
context.location = "/client#/account/profile/interests";
|
||||
}
|
||||
|
||||
function postUpdateProfileFailure(xhr, textStatus, errorMessage) {
|
||||
|
||||
var errors = JSON.parse(xhr.responseText)
|
||||
|
||||
if(xhr.status == 422) {
|
||||
var instruments = context.JK.format_errors("musician_instruments", errors);
|
||||
|
||||
if(instruments != null) {
|
||||
$instrumentSelector.closest('div.field').addClass('error').append(instruments);
|
||||
}
|
||||
}
|
||||
else {
|
||||
app.ajaxError(xhr, textStatus, errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectedInstruments() {
|
||||
var instruments = [];
|
||||
$('input[type=checkbox]:checked', $instrumentSelector).each(function(i) {
|
||||
|
||||
var instrumentElement = $(this).closest('tr');
|
||||
// traverse up to common parent of this instrument, and pick out proficiency selector
|
||||
var proficiency = $('select.proficiency_selector', instrumentElement).val();
|
||||
|
||||
instruments.push({
|
||||
instrument_id: instrumentElement.attr('data-instrument-id'),
|
||||
proficiency_level: proficiency,
|
||||
priority : i
|
||||
});
|
||||
});
|
||||
|
||||
return instruments;
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
|
||||
app.bindScreen('account/profile/experience', screenBindings);
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.beforeShow = beforeShow;
|
||||
this.afterShow = afterShow;
|
||||
return this;
|
||||
};
|
||||
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict"
|
||||
|
||||
context.JK = context.JK || {}
|
||||
context.JK.AccountProfileInterests = function(app) {
|
||||
var $document = $(document)
|
||||
var logger = context.JK.logger
|
||||
var EVENTS = context.JK.EVENTS
|
||||
var api = context.JK.Rest()
|
||||
var ui = new context.JK.UIHelper(JK.app)
|
||||
var user = {}
|
||||
var profileUtils = context.JK.ProfileUtils
|
||||
var masterGenreList = []
|
||||
|
||||
var NONE_SPECIFIED = 'None specified'
|
||||
var GENRE_LIST_DELIMITER = ', '
|
||||
|
||||
var $screen = $('#account-profile-interests')
|
||||
|
||||
var SELECT_GENRE_SELECTOR = '.select-genre'
|
||||
var GENRE_LIST_SELECTOR = '.genre-list'
|
||||
|
||||
// virtual bands
|
||||
var $virtualBandYes = $screen.find('#virtual-band-yes')
|
||||
var $virtualBandNo = $screen.find('#virtual-band-no')
|
||||
var $virtualBandGenres = $screen.find('#virtual-band-genres')
|
||||
var $btnVirtualBandGenreSelect = $virtualBandGenres.find(SELECT_GENRE_SELECTOR)
|
||||
var $virtualBandGenreList = $virtualBandGenres.find(GENRE_LIST_SELECTOR)
|
||||
var $virtualBandCommitment = $screen.find('#virtual-band-commitment')
|
||||
|
||||
// traditional bands
|
||||
var $traditionalBandYes = $screen.find('#traditional-band-yes')
|
||||
var $traditionalBandNo = $screen.find('#traditional-band-no')
|
||||
var $traditionalBandGenres = $screen.find('#traditional-band-genres')
|
||||
var $btnTraditionalBandGenreSelect = $traditionalBandGenres.find(SELECT_GENRE_SELECTOR)
|
||||
var $traditionalBandGenreList = $traditionalBandGenres.find(GENRE_LIST_SELECTOR)
|
||||
var $traditionalBandCommitment = $screen.find('#traditional-band-commitment')
|
||||
var $traditionalTouringOption = $screen.find('#traditional-band-touring')
|
||||
|
||||
// paid sessions
|
||||
var $paidSessionsYes = $screen.find('#paid-sessions-yes')
|
||||
var $paidSessionsNo = $screen.find('#paid-sessions-no')
|
||||
var $paidSessionsGenres = $screen.find('#paid-sessions-genres')
|
||||
var $btnPaidSessionsGenreSelect = $paidSessionsGenres.find(SELECT_GENRE_SELECTOR)
|
||||
var $paidSessionsGenreList = $paidSessionsGenres.find(GENRE_LIST_SELECTOR)
|
||||
var $hourlyRate = $screen.find('#hourly-rate')
|
||||
var $dailyRate = $screen.find('#daily-rate')
|
||||
|
||||
// free sessions
|
||||
var $freeSessionsYes = $screen.find('#free-sessions-yes')
|
||||
var $freeSessionsNo = $screen.find('#free-sessions-no')
|
||||
var $freeSessionsGenres = $screen.find('#free-sessions-genres')
|
||||
var $btnFreeSessionsGenreSelect = $freeSessionsGenres.find(SELECT_GENRE_SELECTOR)
|
||||
var $freeSessionsGenreList = $freeSessionsGenres.find(GENRE_LIST_SELECTOR)
|
||||
|
||||
// cowriting
|
||||
var $cowritingYes = $screen.find('#cowriting-yes')
|
||||
var $cowritingNo = $screen.find('#cowriting-no')
|
||||
var $cowritingGenres = $screen.find('#cowriting-genres')
|
||||
var $btnCowritingGenreSelect = $cowritingGenres.find(SELECT_GENRE_SELECTOR)
|
||||
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')
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
renderInterests()
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
$screen.find('form .error-text').remove()
|
||||
$screen.find('form .error').removeClass("error")
|
||||
}
|
||||
|
||||
function populateAccountProfile(userDetail) {
|
||||
|
||||
// Column 1 - options
|
||||
if (userDetail) {
|
||||
|
||||
if (userDetail.virtual_band) {
|
||||
$virtualBandYes.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
else {
|
||||
$virtualBandNo.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
|
||||
if (userDetail.traditional_band) {
|
||||
$traditionalBandYes.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
else {
|
||||
$traditionalBandNo.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
|
||||
if (userDetail.paid_sessions) {
|
||||
$paidSessionsYes.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
else {
|
||||
$paidSessionsNo.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
|
||||
if (userDetail.free_sessions) {
|
||||
$freeSessionsYes.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
else {
|
||||
$freeSessionsNo.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
|
||||
if (userDetail.cowriting) {
|
||||
$cowritingYes.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
else {
|
||||
$cowritingNo.iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
}
|
||||
|
||||
// Column 2 - genres
|
||||
var genres = profileUtils.virtualBandGenreList(userDetail.genres)
|
||||
$virtualBandGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED)
|
||||
|
||||
genres = profileUtils.traditionalBandGenreList(userDetail.genres)
|
||||
$traditionalBandGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED)
|
||||
|
||||
genres = profileUtils.paidSessionGenreList(userDetail.genres)
|
||||
$paidSessionsGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED)
|
||||
|
||||
genres = profileUtils.freeSessionGenreList(userDetail.genres)
|
||||
$freeSessionsGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED)
|
||||
|
||||
genres = profileUtils.cowritingGenreList(userDetail.genres)
|
||||
$cowritingGenreList.html(genres && genres.length > 0 ? genres : NONE_SPECIFIED)
|
||||
|
||||
// Column 3 - misc (play commitment, rates, cowriting purpose)
|
||||
$virtualBandCommitment.val(userDetail.virtual_band_commitment)
|
||||
context.JK.dropdown($virtualBandCommitment)
|
||||
|
||||
$traditionalBandCommitment.val(userDetail.traditional_band_commitment)
|
||||
context.JK.dropdown($traditionalBandCommitment)
|
||||
|
||||
$traditionalTouringOption.val(userDetail.traditional_band_touring ? '1' : '0')
|
||||
context.JK.dropdown($traditionalTouringOption)
|
||||
|
||||
$hourlyRate.val(userDetail.paid_sessions_hourly_rate)
|
||||
$dailyRate.val(userDetail.paid_sessions_daily_rate)
|
||||
|
||||
$cowritingPurpose.val(userDetail.cowriting_purpose)
|
||||
context.JK.dropdown($cowritingPurpose)
|
||||
}
|
||||
|
||||
function bindGenreSelector(type, $btnSelect, $genreList) {
|
||||
$btnSelect.unbind('click').bind('click', function(e) {
|
||||
e.preventDefault()
|
||||
var genreText = $genreList.html()
|
||||
var genres = []
|
||||
if (genres !== NONE_SPECIFIED) {
|
||||
genres = genreText.split(GENRE_LIST_DELIMITER)
|
||||
}
|
||||
|
||||
ui.launchGenreSelectorDialog(type, genres, function(selectedGenres) {
|
||||
$genreList.html(selectedGenres && selectedGenres.length > 0 ? selectedGenres.join(GENRE_LIST_DELIMITER) : NONE_SPECIFIED)
|
||||
})
|
||||
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
function events() {
|
||||
|
||||
bindGenreSelector('virtual bands', $btnVirtualBandGenreSelect, $virtualBandGenreList)
|
||||
bindGenreSelector('traditional bands', $btnTraditionalBandGenreSelect, $traditionalBandGenreList)
|
||||
bindGenreSelector('paid sessions', $btnPaidSessionsGenreSelect, $paidSessionsGenreList)
|
||||
bindGenreSelector('free sessions', $btnFreeSessionsGenreSelect, $freeSessionsGenreList)
|
||||
bindGenreSelector('co-writing', $btnCowritingGenreSelect, $cowritingGenreList)
|
||||
|
||||
$btnCancel.click(function(e) {
|
||||
e.stopPropagation()
|
||||
navigateTo('/client#/profile/' + context.JK.currentUserId)
|
||||
return false
|
||||
})
|
||||
|
||||
$btnBack.click(function(e) {
|
||||
e.stopPropagation()
|
||||
navigateTo('/client#/account/profile/experience')
|
||||
return false
|
||||
})
|
||||
|
||||
enableSubmits()
|
||||
|
||||
context.JK.dropdown($virtualBandCommitment)
|
||||
context.JK.dropdown($traditionalBandCommitment)
|
||||
context.JK.dropdown($cowritingPurpose)
|
||||
}
|
||||
|
||||
function enableSubmits() {
|
||||
$btnSubmit.on("click", function(e) {
|
||||
e.stopPropagation()
|
||||
handleUpdateProfile()
|
||||
return false
|
||||
})
|
||||
|
||||
$btnSubmit.removeClass("disabled")
|
||||
}
|
||||
|
||||
function disableSubmits() {
|
||||
$btnSubmit.addClass("disabled")
|
||||
$btnSubmit.off("click")
|
||||
}
|
||||
|
||||
function renderInterests() {
|
||||
$.when(api.getUserProfile())
|
||||
.done(function(userDetail) {
|
||||
populateAccountProfile(userDetail)
|
||||
})
|
||||
}
|
||||
|
||||
function navigateTo(targetLocation) {
|
||||
context.location = targetLocation
|
||||
}
|
||||
|
||||
function handleUpdateProfile() {
|
||||
disableSubmits()
|
||||
resetForm()
|
||||
|
||||
api.updateUser({
|
||||
virtual_band: $screen.find('input[name=virtual_band]:checked').val(),
|
||||
virtual_band_genres: $virtualBandGenreList.html() === NONE_SPECIFIED ? [] : $virtualBandGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
virtual_band_commitment: $virtualBandCommitment.val(),
|
||||
|
||||
traditional_band: $screen.find('input[name=traditional_band]:checked').val(),
|
||||
traditional_band_genres: $traditionalBandGenreList.html() === NONE_SPECIFIED ? [] : $traditionalBandGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
traditional_band_commitment: $traditionalBandCommitment.val(),
|
||||
traditional_band_touring: $traditionalTouringOption.val(),
|
||||
|
||||
paid_sessions: $screen.find('input[name=paid_sessions]:checked').val(),
|
||||
paid_session_genres: $paidSessionsGenreList.html() === NONE_SPECIFIED ? [] : $paidSessionsGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
paid_sessions_hourly_rate: $hourlyRate.val(),
|
||||
paid_sessions_daily_rate: $dailyRate.val(),
|
||||
|
||||
free_sessions: $screen.find('input[name=free_sessions]:checked').val(),
|
||||
free_session_genre: $freeSessionsGenreList.html() === NONE_SPECIFIED ? [] : $freeSessionsGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
|
||||
cowriting: $screen.find('input[name=cowriting]:checked').val(),
|
||||
cowriting_genres: $cowritingGenreList.html() === NONE_SPECIFIED ? [] : $cowritingGenreList.html().split(GENRE_LIST_DELIMITER),
|
||||
cowriting_purpose: $cowritingPurpose.val()
|
||||
})
|
||||
.done(postUpdateProfileSuccess)
|
||||
.fail(postUpdateProfileFailure)
|
||||
.always(enableSubmits)
|
||||
}
|
||||
|
||||
function postUpdateProfileSuccess(response) {
|
||||
$document.triggerHandler(EVENTS.USER_UPDATED, response)
|
||||
context.location = "/client#/account/profile/samples"
|
||||
}
|
||||
|
||||
function postUpdateProfileFailure(xhr, textStatus, errorMessage) {
|
||||
|
||||
var errors = JSON.parse(xhr.responseText)
|
||||
|
||||
if(xhr.status == 422) {
|
||||
|
||||
}
|
||||
else {
|
||||
app.ajaxError(xhr, textStatus, errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
}
|
||||
|
||||
app.bindScreen('account/profile/interests', screenBindings)
|
||||
|
||||
events()
|
||||
|
||||
$screen.find('.interest-options').iCheck({
|
||||
checkboxClass: 'icheckbox_minimal',
|
||||
radioClass: 'iradio_minimal',
|
||||
inheritClass: true
|
||||
})
|
||||
|
||||
profileUtils.initializeHelpBubbles($screen)
|
||||
}
|
||||
|
||||
this.initialize = initialize
|
||||
this.beforeShow = beforeShow
|
||||
this.afterShow = afterShow
|
||||
return this
|
||||
}
|
||||
|
||||
})(window,jQuery)
|
||||
|
|
@ -0,0 +1,487 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
|
||||
// TODO: Add a target type, which can be band or user -- call the
|
||||
// appropriate API methods.
|
||||
context.JK.AccountProfileSamples = function(app, parent, loadFn, updateFn) {
|
||||
var $document = $(document)
|
||||
|
||||
// used to initialize RecordingSourceValidator in site_validator.js.coffee
|
||||
var jamkazamRecordingSources = [];
|
||||
var soundCloudRecordingSources = [];
|
||||
var youTubeRecordingSources = [];
|
||||
|
||||
var logger = context.JK.logger;
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var api = context.JK.Rest();
|
||||
var ui = new context.JK.UIHelper(JK.app);
|
||||
var target = {};
|
||||
var profileUtils = context.JK.ProfileUtils;
|
||||
var $screen = $('.profile-online-sample-controls', parent);
|
||||
// online presences
|
||||
var $website = $screen.find('.website');
|
||||
var $soundCloudUsername = $screen.find('.soundcloud-username');
|
||||
var $reverbNationUsername = $screen.find('.reverbnation-username');
|
||||
var $bandCampUsername = $screen.find('.bandcamp-username');
|
||||
var $fandalismUsername = $screen.find('.fandalism-username');
|
||||
var $youTubeUsername = $screen.find('.youtube-username');
|
||||
var $facebookUsername = $screen.find('.facebook-username');
|
||||
var $twitterUsername = $screen.find('.twitter-username');
|
||||
|
||||
// performance samples
|
||||
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 = 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) {
|
||||
$.when(loadFn())
|
||||
.done(function(targetPlayer) {
|
||||
if (targetPlayer && targetPlayer.keys && targetPlayer.keys.length > 0) {
|
||||
renderPlayer(targetPlayer)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function renderPlayer(targetPlayer) {
|
||||
renderPresence(targetPlayer);
|
||||
renderSamples(targetPlayer);
|
||||
}
|
||||
|
||||
function renderPresence(targetPlayer) {
|
||||
$website.val(targetPlayer.website);
|
||||
|
||||
// SoundCloud
|
||||
var presences = profileUtils.soundCloudPresences(targetPlayer.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$soundCloudUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// ReverbNation
|
||||
presences = profileUtils.reverbNationPresences(targetPlayer.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$reverbNationUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// Bandcamp
|
||||
presences = profileUtils.bandCampPresences(targetPlayer.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$bandCampUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// Fandalism
|
||||
presences = profileUtils.fandalismPresences(targetPlayer.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$fandalismUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// YouTube
|
||||
presences = profileUtils.youTubePresences(targetPlayer.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$youTubeUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// Facebook
|
||||
presences = profileUtils.facebookPresences(targetPlayer.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$facebookUsername.val(presences[0].username);
|
||||
}
|
||||
|
||||
// Twitter
|
||||
presences = profileUtils.twitterPresences(targetPlayer.online_presences);
|
||||
if (presences && presences.length > 0) {
|
||||
$twitterUsername.val(presences[0].username);
|
||||
}
|
||||
}
|
||||
|
||||
function renderSamples(targetPlayer) {
|
||||
// JamKazam recordings
|
||||
var samples = profileUtils.jamkazamSamples(targetPlayer.performance_samples);
|
||||
loadSamples(samples, 'jamkazam', $jamkazamSampleList, jamkazamRecordingSources);
|
||||
|
||||
// SoundCloud recordings
|
||||
samples = profileUtils.soundCloudSamples(targetPlayer.performance_samples);
|
||||
loadSamples(samples, 'soundcloud', $soundCloudSampleList, soundCloudRecordingSources);
|
||||
|
||||
// YouTube videos
|
||||
samples = profileUtils.youTubeSamples(targetPlayer.performance_samples);
|
||||
loadSamples(samples, 'youtube', $youTubeSampleList, youTubeRecordingSources);
|
||||
}
|
||||
|
||||
function loadSamples(samples, type, $sampleList, recordingSources) {
|
||||
$sampleList.find(":not(.empty)").remove();
|
||||
|
||||
if (type === 'jamkazam') {
|
||||
$.each(samples, function(index, val) {
|
||||
recordingSources.push({
|
||||
'claimed_recording_id': val.claimed_recording.id,
|
||||
'description': val.claimed_recording.name
|
||||
});
|
||||
|
||||
buildJamkazamEntry(val.claimed_recording.id, val.claimed_recording.name);
|
||||
});
|
||||
} else {
|
||||
if (samples && samples.length > 0) {
|
||||
$.each(samples, function(index, val) {
|
||||
|
||||
recordingSources.push({
|
||||
'url': val.url,
|
||||
'recording_id': val.service_id,
|
||||
'recording_title': val.description
|
||||
});
|
||||
|
||||
// TODO: this code is repeated in HTML file
|
||||
var recordingIdAttr = ' data-recording-id="' + val.service_id + '" ';
|
||||
var recordingUrlAttr = ' data-recording-url="' + val.url + '" ';
|
||||
var recordingTitleAttr = ' data-recording-title="' + val.description + '"';
|
||||
var title = formatTitle(val.description);
|
||||
$sampleList.append('<div class="clearall recording-row left entry"' + recordingIdAttr + recordingUrlAttr + recordingTitleAttr + '>' + title + '</div>');
|
||||
$sampleList.append('<div class="right close-button" data-recording-type="' + type + '"' + recordingIdAttr + '>X</div>');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildJamkazamEntry(recordingId, recordingName) {
|
||||
var title = formatTitle(recordingName);
|
||||
|
||||
var recordingIdAttr = ' data-recording-id="' + recordingId + '" ';
|
||||
$jamkazamSampleList.append('<div class="clearall recording-row left entry"' + recordingIdAttr + '>' + title + '</div>');
|
||||
$jamkazamSampleList.append('<div class="right close-button" data-recording-type="jamkazam"' + recordingIdAttr + '>X</div>');
|
||||
}
|
||||
|
||||
function events() {
|
||||
|
||||
// buttons
|
||||
$btnAddJkRecording.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
// retrieve recordings and pass to modal dialog
|
||||
api.getClaimedRecordings()
|
||||
.done(function(response) {
|
||||
ui.launchRecordingSelectorDialog(response, jamkazamRecordingSources, function(selectedRecordings) {
|
||||
$jamkazamSampleList.empty();
|
||||
|
||||
jamkazamRecordingSources = [];
|
||||
|
||||
// update the list with the selected recordings
|
||||
$.each(selectedRecordings, function(index, val) {
|
||||
jamkazamRecordingSources.push({
|
||||
'claimed_recording_id': val.id,
|
||||
'description': val.name
|
||||
});
|
||||
|
||||
buildJamkazamEntry(val.id, val.name);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnCancel.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/profile/' + context.JK.currentUserId);
|
||||
return false;
|
||||
});
|
||||
|
||||
$btnBack.click(function(evt) {
|
||||
evt.stopPropagation();
|
||||
navigateTo('/client#/account/profile/interests');
|
||||
return false;
|
||||
});
|
||||
|
||||
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.off("click").on("click", function(e) {
|
||||
e.stopPropagation();
|
||||
handleUpdateProfile();
|
||||
return false;
|
||||
})
|
||||
|
||||
$btnSubmit.removeClass("disabled")
|
||||
}
|
||||
|
||||
function disableSubmits() {
|
||||
$btnSubmit.addClass("disabled")
|
||||
$btnSubmit.off("click")
|
||||
}
|
||||
|
||||
function validate() {
|
||||
var errors = $screen.find('.site_validator.error');
|
||||
return !(errors && errors.length > 0);
|
||||
}
|
||||
|
||||
function navigateTo(targetLocation) {
|
||||
context.location = targetLocation;
|
||||
}
|
||||
|
||||
function addOnlinePresence(presenceArray, username, type) {
|
||||
if ($.trim(username).length > 0) {
|
||||
presenceArray.push({
|
||||
'player_id': context.JK.currentUserId,
|
||||
'service_type': type,
|
||||
'username': username
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addPerformanceSamples(sampleArray, $samplesSelector, type) {
|
||||
var rows = $samplesSelector.find('.recording-row');
|
||||
|
||||
// loop over rows, extracting service id, description, and url
|
||||
rows.each(function(index) {
|
||||
var id = $(this).attr('data-recording-id');
|
||||
|
||||
if (type === 'jamkazam') {
|
||||
sampleArray.push({
|
||||
'player_id': context.JK.currentUserId,
|
||||
'service_type': type,
|
||||
'claimed_recording_id': id,
|
||||
});
|
||||
} else {
|
||||
var url = $(this).attr('data-recording-url');
|
||||
var title = $(this).attr('data-recording-title');
|
||||
|
||||
sampleArray.push({
|
||||
'player_id': context.JK.currentUserId,
|
||||
'service_type': type,
|
||||
'service_id': id,
|
||||
'url': url,
|
||||
'description': title
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleUpdateProfile() {
|
||||
disableSubmits()
|
||||
|
||||
var player = buildPlayer()
|
||||
updateFn({
|
||||
website: player.website,
|
||||
online_presences: player.online_presences,
|
||||
performance_samples: player.performance_samples
|
||||
})
|
||||
.done(postUpdateProfileSuccess)
|
||||
.fail(postUpdateProfileFailure)
|
||||
.always(enableSubmits);
|
||||
}
|
||||
|
||||
function buildPlayer() {
|
||||
// extract online presences
|
||||
var op = [];
|
||||
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);
|
||||
addOnlinePresence(op, $fandalismUsername.val(), presenceTypes.FANDALISM.description);
|
||||
addOnlinePresence(op, $youTubeUsername.val(), presenceTypes.YOUTUBE.description);
|
||||
addOnlinePresence(op, $facebookUsername.val(), presenceTypes.FACEBOOK.description);
|
||||
addOnlinePresence(op, $twitterUsername.val(), presenceTypes.TWITTER.description);
|
||||
|
||||
// extract performance samples
|
||||
var ps = [];
|
||||
var performanceSampleTypes = profileUtils.SAMPLE_TYPES;
|
||||
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) {
|
||||
$document.triggerHandler(EVENTS.USER_UPDATED, response);
|
||||
context.location = "/client#/profile/" + context.JK.currentUserId;
|
||||
}
|
||||
|
||||
function postUpdateProfileFailure(xhr, textStatus, errorMessage) {
|
||||
|
||||
var errors = JSON.parse(xhr.responseText)
|
||||
|
||||
if(xhr.status == 422) {
|
||||
|
||||
} 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') {
|
||||
soundCloudRecordingValidator.removeRecordingId(recordingId);
|
||||
} else if (type === 'youtube') {
|
||||
youTubeRecordingValidator.removeRecordingId(recordingId);
|
||||
}
|
||||
}
|
||||
|
||||
function formatTitle(title) {
|
||||
return title && title.length > 30 ? title.substring(0, 30) + "..." : title;
|
||||
}
|
||||
|
||||
// This function is a bit of a mess. It was pulled
|
||||
// from the html.erb file verbatim, and could use a
|
||||
// refactor:
|
||||
function initializeValidators() {
|
||||
var initialized = false;
|
||||
//$document.on('JAMKAZAM_READY', function(e, data) {
|
||||
JK.JamServer.get$Server().on(JK.EVENTS.CONNECTION_UP, function() {
|
||||
if(initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
//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');
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
urlValidator = new JK.SiteValidator('url', userNameSuccessCallback, userNameFailCallback, parent)
|
||||
urlValidator.init()
|
||||
|
||||
soundCloudValidator = new JK.SiteValidator('soundcloud', userNameSuccessCallback, userNameFailCallback, parent)
|
||||
soundCloudValidator.init()
|
||||
|
||||
reverbNationValidator = new JK.SiteValidator('reverbnation', userNameSuccessCallback, userNameFailCallback, parent)
|
||||
reverbNationValidator.init()
|
||||
|
||||
bandCampValidator = new JK.SiteValidator('bandcamp', userNameSuccessCallback, userNameFailCallback, parent)
|
||||
bandCampValidator.init()
|
||||
|
||||
fandalismValidator = new JK.SiteValidator('fandalism', userNameSuccessCallback, userNameFailCallback, parent)
|
||||
fandalismValidator.init()
|
||||
|
||||
youTubeValidator = new JK.SiteValidator('youtube', userNameSuccessCallback, userNameFailCallback, parent)
|
||||
youTubeValidator.init()
|
||||
|
||||
facebookValidator = new JK.SiteValidator('facebook', userNameSuccessCallback, userNameFailCallback, parent)
|
||||
facebookValidator.init()
|
||||
|
||||
twitterValidator = new JK.SiteValidator('twitter', userNameSuccessCallback, userNameFailCallback, parent)
|
||||
twitterValidator.init()
|
||||
|
||||
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) {
|
||||
$inputDiv.addClass('error');
|
||||
$inputDiv.find('.error-text').remove();
|
||||
$inputDiv.append("<span class='error-text'>Invalid username</span>").show();
|
||||
}
|
||||
|
||||
function soundCloudSuccessCallback($inputDiv) {
|
||||
siteSuccessCallback($inputDiv, soundCloudRecordingValidator, $soundCloudSampleList, 'soundcloud');
|
||||
}
|
||||
|
||||
function youTubeSuccessCallback($inputDiv) {
|
||||
siteSuccessCallback($inputDiv, youTubeRecordingValidator, $youTubeSampleList, 'youtube');
|
||||
}
|
||||
|
||||
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 addedRecording = recordingSources[recordingSources.length-1];
|
||||
|
||||
// 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('<div class="clearall recording-row left entry"' + recordingIdAttr + recordingUrlAttr + recordingTitleAttr + '>' + title + '</div>');
|
||||
sampleList.append('<div class="right close-button" data-recording-type="' + type + '"' + recordingIdAttr + '>X</div>');
|
||||
}
|
||||
|
||||
$inputDiv.find('input').val('');
|
||||
}
|
||||
|
||||
function siteFailCallback($inputDiv) {
|
||||
$inputDiv.addClass('error');
|
||||
$inputDiv.find('.error-text').remove();
|
||||
$inputDiv.append("<span class='error-text'>Invalid URL</span>").show();
|
||||
}
|
||||
});
|
||||
//});
|
||||
|
||||
|
||||
|
||||
} // end initializeValidators.
|
||||
|
||||
function resetForm() {
|
||||
$("input", $screen).val("")
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
|
||||
app.bindScreen('account/profile/samples', screenBindings);
|
||||
initializeValidators();
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.beforeShow = beforeShow;
|
||||
this.afterShow = afterShow;
|
||||
this.buildPlayer = buildPlayer;
|
||||
this.renderPlayer = renderPlayer
|
||||
this.resetForm = resetForm;
|
||||
return this;
|
||||
};
|
||||
})(window,jQuery);
|
||||
|
|
@ -9,24 +9,107 @@
|
|||
// accounts_profiles.js
|
||||
|
||||
context.JK.BandSetupScreen = function (app) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var inviteMusiciansUtil = null;
|
||||
var invitationDialog = null;
|
||||
var autoComplete = null;
|
||||
var userNames = [];
|
||||
var userIds = [];
|
||||
var userPhotoUrls = [];
|
||||
var selectedFriendIds = {};
|
||||
var nilOptionStr = '<option value=""></option>';
|
||||
var nilOptionText = 'n/a';
|
||||
var bandId = '';
|
||||
var friendInput=null;
|
||||
var step1, step2;
|
||||
var isSaving = false;
|
||||
var NONE_SPECIFIED = 'None specified'
|
||||
var GENRE_STEP = 1
|
||||
var SAMPLE_STEP = 3
|
||||
var STEPS_COUNT = 5
|
||||
var currentStep = 0
|
||||
var ui = new context.JK.UIHelper(JK.app)
|
||||
var logger = context.JK.logger
|
||||
var profileUtils = context.JK.ProfileUtils
|
||||
var rest = context.JK.Rest()
|
||||
var inviteMusiciansUtil = null
|
||||
var invitationDialog = null
|
||||
var autoComplete = null
|
||||
var userNames = []
|
||||
var userIds = []
|
||||
var userPhotoUrls = []
|
||||
var selectedFriendIds = {}
|
||||
var nilOptionStr = '<option value=""></option>'
|
||||
var nilOptionText = 'n/a'
|
||||
var bandId = ''
|
||||
var friendInput=null
|
||||
var bandType=null
|
||||
var bandStatus=null
|
||||
var concertCount=null
|
||||
|
||||
function is_new_record() {
|
||||
return bandId.length == 0;
|
||||
|
||||
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()
|
||||
|
||||
function navBack() {
|
||||
if (currentStep>0) {
|
||||
saveBand(function() {
|
||||
currentStep--
|
||||
renderCurrentPage()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function navCancel() {
|
||||
resetForm()
|
||||
window.history.go(-1)
|
||||
return false
|
||||
}
|
||||
|
||||
function navNext() {
|
||||
if (currentStep<STEPS_COUNT-1) {
|
||||
saveBand(function(band) {
|
||||
currentStep++
|
||||
renderCurrentPage()
|
||||
})
|
||||
} else {
|
||||
saveBand(function(band) {
|
||||
resetForm()
|
||||
showProfile(band.id);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function renderCurrentPage() {
|
||||
$screen.find($(".band-step")).addClass("hidden")
|
||||
$("#band-setup-step-" + currentStep).removeClass("hidden")
|
||||
if(currentStep==0) {
|
||||
$("#btn-band-setup-back").addClass("hidden")
|
||||
$("#btn-band-setup-next").removeClass("hidden").html("SAVE & NEXT")
|
||||
} else if(currentStep<STEPS_COUNT-1) {
|
||||
// if(currentStep==SAMPLE_STEP) {
|
||||
// accountProfileSamples.renderPlayer(band)
|
||||
// }
|
||||
$("#btn-band-setup-back").removeClass("hidden")
|
||||
$("#btn-band-setup-next").removeClass("hidden").html("SAVE & NEXT")
|
||||
} else {
|
||||
$("#btn-band-setup-back").removeClass("hidden")
|
||||
$("#btn-band-setup-next").removeClass("hidden").html("SAVE & FINISH")
|
||||
}
|
||||
renderOptionalControls()
|
||||
}
|
||||
|
||||
function renderOptionalControls(e) {
|
||||
if(e){e.stopPropagation()}
|
||||
|
||||
// Is new member selected?
|
||||
if ($screen.find($('input[name="add_new_members"]:checked')).val()=="yes") {
|
||||
$screen.find($(".new-member-dependent")).removeClass("hidden")
|
||||
} else {
|
||||
$screen.find($(".new-member-dependent")).addClass("hidden")
|
||||
}
|
||||
|
||||
// Is paid gigs selected?
|
||||
if ($('input[name="paid_gigs"]:checked').val()=="yes") {
|
||||
$screen.find($(".paid-gigs-dependent")).removeClass("hidden")
|
||||
} else {
|
||||
$screen.find($(".paid-gigs-dependent")).addClass("hidden")
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isNewBand() {
|
||||
return bandId==null || typeof(bandId)=='undefined' || bandId.length == 0;
|
||||
}
|
||||
|
||||
function removeErrors() {
|
||||
|
|
@ -38,6 +121,7 @@
|
|||
function resetForm() {
|
||||
|
||||
removeErrors();
|
||||
accountProfileSamples.resetForm()
|
||||
|
||||
// name
|
||||
$("#band-name").val('');
|
||||
|
|
@ -60,10 +144,17 @@
|
|||
// website
|
||||
$('#band-website').val('');
|
||||
|
||||
resetGenres();
|
||||
$("#new-member-no").iCheck('check').attr('checked', 'checked')
|
||||
$("#paid-gigs-no").iCheck('check').attr('checked', 'checked')
|
||||
$("#free-gigs-no").iCheck('check').attr('checked', 'checked')
|
||||
$('#touring-option').val('no')
|
||||
|
||||
$("#band-setup-step-1").show();
|
||||
$("#band-setup-step-2").hide();
|
||||
|
||||
$("#play-commitment").val('1')
|
||||
$("#hourly-rate").val("0.0")
|
||||
$("#gig-minimum").val("0.0")
|
||||
resetGenres();
|
||||
renderDesiredExperienceLabel([])
|
||||
|
||||
$(friendInput)
|
||||
.unbind('blur')
|
||||
|
|
@ -93,102 +184,144 @@
|
|||
removeErrors();
|
||||
|
||||
var band = buildBand();
|
||||
|
||||
return rest.validateBand(band);
|
||||
}
|
||||
|
||||
function renderErrors(errors) {
|
||||
logger.debug("Band setup errors: ", errors)
|
||||
var name = context.JK.format_errors("name", errors);
|
||||
var country = context.JK.format_errors("country", errors);
|
||||
var state = context.JK.format_errors("state", errors);
|
||||
var city = context.JK.format_errors("city", errors);
|
||||
var biography = context.JK.format_errors("biography", errors);
|
||||
var genres = context.JK.format_errors("genres", errors);
|
||||
var website = context.JK.format_errors("website", errors);
|
||||
var genres = context.JK.format_errors("genres", errors);
|
||||
|
||||
if(name) $("#band-name").closest('div.field').addClass('error').end().after(name);
|
||||
if(country) $("#band-country").closest('div.field').addClass('error').end().after(country);
|
||||
if(state) $("#band-region").closest('div.field').addClass('error').end().after(state);
|
||||
if(city) $("#band-city").closest('div.field').addClass('error').end().after(city);
|
||||
if(genres) $(".band-setup-genres").closest('div.field').addClass('error').end().after(genres);
|
||||
if(name) $("#band-name").closest('div.field').addClass('error').end().after(name);
|
||||
if(country) $("#band-country").closest('div.field').addClass('error').end().after(country);
|
||||
if(state) $("#band-region").closest('div.field').addClass('error').end().after(state);
|
||||
if(city) $("#band-city").closest('div.field').addClass('error').end().after(city);
|
||||
if(biography) $("#band-biography").closest('div.field').addClass('error').end().after(biography);
|
||||
if(website) $("#band-website").closest('div.field').addClass('error').end().after(website);
|
||||
if(website) $("#band-website").closest('div.field').addClass('error').end().after(website);
|
||||
if(genres) $("#band-genres").closest('div.field').addClass('error').end().after(genres);
|
||||
}
|
||||
|
||||
function buildBand() {
|
||||
var band = {};
|
||||
var band = {instruments:[]};
|
||||
band.id = (isNewBand()) ? null : bandId;
|
||||
band.name = $("#band-name").val();
|
||||
band.website = $("#band-website").val();
|
||||
band.biography = $("#band-biography").val();
|
||||
band.city = $("#band-city").val();
|
||||
band.state = $("#band-region").val();
|
||||
band.country = $("#band-country").val();
|
||||
band.genres = getSelectedGenres();
|
||||
|
||||
band.band_type = bandType.val();
|
||||
band.band_status= bandStatus.val();
|
||||
band.concert_count= concertCount.val();
|
||||
|
||||
band.add_new_members = $('input[name="add_new_members"]:checked').val()=="yes"
|
||||
band.paid_gigs = $('input[name="paid_gigs"]:checked').val()=="yes"
|
||||
band.free_gigs=$('input[name="free_gigs"]:checked').val()=="yes"
|
||||
band.touring_option=$('#touring-option').val()=="yes"
|
||||
|
||||
band.play_commitment=$("#play-commitment").val()
|
||||
band.hourly_rate=$("#hourly-rate").val()
|
||||
band.gig_minimum=$("#gig-minimum").val()
|
||||
|
||||
if (currentStep==GENRE_STEP) {
|
||||
band.genres = getSelectedGenres();
|
||||
band.validate_genres = true
|
||||
} else {
|
||||
band.validate_genres = false
|
||||
}
|
||||
|
||||
$.each($selectedInstruments, function(index, instrument) {
|
||||
var h = {}
|
||||
h.instrument_id = instrument.id
|
||||
h.proficiency_level = instrument.level
|
||||
band.instruments.push(h)
|
||||
})
|
||||
|
||||
if(!isNewBand()) {
|
||||
mergePerformanceSamples(band)
|
||||
}
|
||||
|
||||
return band;
|
||||
}
|
||||
|
||||
function mergePerformanceSamples(band) {
|
||||
// Collect and merge data from this sub-widget:
|
||||
var performanceSampleData = accountProfileSamples.buildPlayer()
|
||||
band.website=performanceSampleData.website
|
||||
band.online_presences=performanceSampleData.online_presences
|
||||
band.performance_samples=performanceSampleData.performance_samples
|
||||
|
||||
// Change player id to that of band. Widget currently hardwires current user id:
|
||||
if(band.online_presences) {
|
||||
for (var i=0; i<band.online_presences.length; ++i) {
|
||||
band.online_presences[i].player_id = band.id
|
||||
}
|
||||
}
|
||||
|
||||
// Change player id to that of band. Widget currently hardwires current user id:
|
||||
if(band.performance_samples) {
|
||||
for (var i=0; i<band.performance_samples.length; ++i) {
|
||||
band.performance_samples[i].player_id = band.id
|
||||
}
|
||||
}
|
||||
|
||||
return band
|
||||
}
|
||||
|
||||
function renderDesiredExperienceLabel(selectedInstruments) {
|
||||
$selectedInstruments=selectedInstruments
|
||||
var instrumentText=""
|
||||
$.each($selectedInstruments, function(index, instrument) {
|
||||
if (instrumentText.length!=0) {instrumentText += ", "}
|
||||
instrumentText += instrument.name
|
||||
})
|
||||
|
||||
$("#desired-experience-label").html(($selectedInstruments && $selectedInstruments.length > 0) ? instrumentText : NONE_SPECIFIED)
|
||||
}
|
||||
|
||||
function showProfile(band_id) {
|
||||
context.location = "/client#/bandProfile/" + band_id;
|
||||
}
|
||||
|
||||
function saveBand() {
|
||||
if (isSaving) return;
|
||||
isSaving = true;
|
||||
function saveInvitations(response) {
|
||||
if (0 < $('#selected-friends-band .invitation').length) {
|
||||
createBandInvitations(response.id, function () {
|
||||
showProfile(response.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function saveBand(saveBandSuccessFn) {
|
||||
|
||||
unbindNavButtons()
|
||||
removeErrors()
|
||||
var band = buildBand()
|
||||
|
||||
if (is_new_record()) {
|
||||
rest.createBand(band)
|
||||
.done(function (response) {
|
||||
isSaving = false;
|
||||
if (0 < $('#selected-friends-band .invitation').length) {
|
||||
createBandInvitations(response.id, function () {
|
||||
showProfile(response.id);
|
||||
});
|
||||
} else
|
||||
showProfile(response.id);
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
isSaving = false;
|
||||
app.notifyServerError(jqXHR, "Unable to create band")
|
||||
});
|
||||
;
|
||||
}
|
||||
else {
|
||||
band.id = bandId;
|
||||
if (!step1 && !step2){
|
||||
rest.updateBand(band)
|
||||
.done(function (response) {
|
||||
isSaving = false;
|
||||
createBandInvitations(band.id, function () {
|
||||
showProfile(band.id);
|
||||
});
|
||||
}).fail(function (jqXHR) {
|
||||
isSaving = false;
|
||||
app.notifyServerError(jqXHR, "Unable to create band")
|
||||
});
|
||||
} else {
|
||||
if (step1) {
|
||||
rest.updateBand(band)
|
||||
.done(function (response) {
|
||||
isSaving = false;
|
||||
app.notifyAlert('Band Information', 'Your changes have been saved');
|
||||
}).fail(function (jqXHR) {
|
||||
isSaving = false;
|
||||
app.notifyServerError(jqXHR, "Unable to update band")
|
||||
});
|
||||
} else if (step2) {
|
||||
isSaving = false;
|
||||
if (0 < $('#selected-friends-band .invitation').length) {
|
||||
createBandInvitations(bandId, function () {
|
||||
app.notifyAlert('Band Members', 'Your invitations have been sent');
|
||||
showProfile(bandId);
|
||||
});
|
||||
} else
|
||||
showProfile(bandId);
|
||||
var saveBandFn = (isNewBand()) ? rest.createBand : rest.updateBand
|
||||
saveBandFn(band)
|
||||
.done(function (response) {
|
||||
bandId = response.id
|
||||
saveInvitations(response)
|
||||
if(saveBandSuccessFn) {
|
||||
saveBandSuccessFn(band)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
renderErrors(JSON.parse(jqXHR.responseText))
|
||||
} else {
|
||||
app.notifyServerError(jqXHR, "Unable to create band")
|
||||
}
|
||||
})
|
||||
.always(function (jqXHR) {
|
||||
bindNavButtons()
|
||||
})
|
||||
}
|
||||
|
||||
function createBandInvitations(bandId, onComplete) {
|
||||
|
|
@ -219,14 +352,13 @@
|
|||
function beforeShow(data) {
|
||||
inviteMusiciansUtil.clearSelections();
|
||||
bandId = data.id == 'new' ? '' : data.id;
|
||||
|
||||
step1 = step2 = false;
|
||||
if ('step2'==data['d']) {
|
||||
step2 = true;
|
||||
delete data['d'];
|
||||
} else if ('step1'==data['d']){
|
||||
step1 = true;
|
||||
currentStep=0
|
||||
if (data['d']) {
|
||||
var stepNum = data['d'].substring(4)
|
||||
if(stepNum) {
|
||||
currentStep=stepNum
|
||||
delete data['d'];
|
||||
}
|
||||
}
|
||||
resetForm();
|
||||
}
|
||||
|
|
@ -234,61 +366,68 @@
|
|||
function afterShow(data) {
|
||||
inviteMusiciansUtil.loadFriends();
|
||||
|
||||
if (!is_new_record()) {
|
||||
$("#band-setup-title").html("edit band");
|
||||
$("#btn-band-setup-save").html("SAVE CHANGES");
|
||||
if (!isNewBand()) {
|
||||
$("#band-change-photo").html('Upload band photo.');
|
||||
$('#tdBandPhoto').css('visibility', 'visible');
|
||||
$('.band-photo').removeClass("hidden")
|
||||
|
||||
// retrieve and initialize band profile data points
|
||||
loadBandDetails();
|
||||
|
||||
if (step2) {
|
||||
$("#band-setup-step-2").show();
|
||||
$("#band-setup-step-1").hide();
|
||||
$('.band-setup-text-step2').each(function(idx) { $(this).hide(); });
|
||||
$('#btn-band-setup-back').text('CANCEL');
|
||||
$('#btn-band-setup-save').text('SEND INVITATIONS');
|
||||
|
||||
} else if (step1) {
|
||||
$("#band-setup-step-1").show();
|
||||
$("#band-setup-step-2").hide();
|
||||
$('.band-setup-text-step1').each(function(idx) { $(this).hide(); });
|
||||
$('#btn-band-setup-next').text('SAVE');
|
||||
}
|
||||
if (! step1 && ! step2) {
|
||||
$('#btn-band-setup-next').text('NEXT');
|
||||
$('#btn-band-setup-back').text('CANCEL');
|
||||
$('#btn-band-setup-save').text('CREATE BAND');
|
||||
$('.band-setup-text-step1').each(function(idx) { $(this).show(); });
|
||||
$('.band-setup-text-step2').each(function(idx) { $(this).show(); });
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
loadGenres();
|
||||
|
||||
rest.getResolvedLocation()
|
||||
.done(function (location) {
|
||||
loadCountries(location.country, function () {
|
||||
loadRegions(location.region, function () {
|
||||
loadCities(location.city);
|
||||
});
|
||||
// Load geo settings:
|
||||
rest.getResolvedLocation().done(function (location) {
|
||||
loadCountries(location.country, function () {
|
||||
loadRegions(location.region, function () {
|
||||
loadCities(location.city);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("#band-setup-title").html("set up band");
|
||||
$("#btn-band-setup-save").html("CREATE BAND");
|
||||
$('#tdBandPhoto').css('visibility', 'hidden'); // can't upload photo when going through initial setup
|
||||
$('.band-photo').addClass("hidden")
|
||||
}
|
||||
renderCurrentPage()
|
||||
}
|
||||
|
||||
function loadDesiredExperience() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
function loadBandDetails() {
|
||||
rest.getBand(bandId).done(function (band) {
|
||||
$("#band-name").val(band.name);
|
||||
$("#band-website").val(band.website);
|
||||
$("#band-biography").val(band.biography);
|
||||
|
||||
bandType.val(band.band_type)
|
||||
bandStatus.val(band.band_status)
|
||||
concertCount.val(band.concert_count)
|
||||
|
||||
if (band.add_new_members){
|
||||
$("#new-member-no").iCheck('check').attr('checked', 'checked')
|
||||
} else {
|
||||
$("#new-member-yes").iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
|
||||
if (band.paid_gigs) {
|
||||
$("#paid-gigs-no").iCheck('check').attr('checked', 'checked')
|
||||
} else {
|
||||
$("#paid-gigs-yes").iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
|
||||
if (band.free_gigs) {
|
||||
$("#free-gigs-no").iCheck('check').attr('checked', 'checked')
|
||||
} else {
|
||||
$("#free-gigs-yes").iCheck('check').attr('checked', 'checked')
|
||||
}
|
||||
|
||||
$('#touring-option').val(band.touring_option ? 'yes' : 'no')
|
||||
$("#play-commitment").val(band.play_commitment)
|
||||
$("#hourly-rate").val(band.hourly_rate)
|
||||
$("#gig-minimum").val(band.gig_minimum)
|
||||
|
||||
// Initialize avatar
|
||||
if (band.photo_url) {
|
||||
$("#band-avatar").attr('src', band.photo_url);
|
||||
}
|
||||
|
|
@ -301,7 +440,20 @@
|
|||
});
|
||||
});
|
||||
|
||||
// TODO: initialize avatar
|
||||
renderOptionalControls();
|
||||
|
||||
$.each(band.instruments, function(index, instrument) {
|
||||
var h = {}
|
||||
h.id = instrument.instrument_id
|
||||
h.level = instrument.proficiency_level
|
||||
h.approve = true
|
||||
$selectedInstruments.push(h)
|
||||
})
|
||||
|
||||
renderDesiredExperienceLabel($selectedInstruments)
|
||||
|
||||
accountProfileSamples.renderPlayer(band)
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -432,7 +584,7 @@
|
|||
} else {
|
||||
context.JK.dropdown($city);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addInvitation(value, data) {
|
||||
if ($('#selected-band-invitees div[user-id=' + data + ']').length === 0) {
|
||||
|
|
@ -441,8 +593,7 @@
|
|||
$('#selected-band-invitees').append(invitationHtml);
|
||||
$('#band-invitee-input').select();
|
||||
selectedFriendIds[data] = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$('#band-invitee-input').select();
|
||||
context.alert('Invitation already exists for this musician.');
|
||||
}
|
||||
|
|
@ -453,58 +604,55 @@
|
|||
context.location = '/client#/band/setup/photo/' + bandId;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function removeInvitation(evt) {
|
||||
delete selectedFriendIds[$(evt.currentTarget).parent().attr('user-id')];
|
||||
$(evt.currentTarget).closest('.invitation').remove();
|
||||
}
|
||||
|
||||
function bindNavButtons() {
|
||||
$('#btn-band-setup-back').on("click", function (e) {
|
||||
e.stopPropagation()
|
||||
navBack()
|
||||
return false
|
||||
})
|
||||
|
||||
$('#btn-band-setup-cancel').on("click", function (e) {
|
||||
e.stopPropagation()
|
||||
navCancel()
|
||||
return false
|
||||
})
|
||||
|
||||
$('#btn-band-setup-next').on("click", function (e) {
|
||||
e.stopPropagation()
|
||||
navNext()
|
||||
return false
|
||||
})
|
||||
|
||||
$('#btn-band-setup-back').removeClass("disabled")
|
||||
$('#btn-band-setup-cancel').removeClass("disabled")
|
||||
$('#btn-band-setup-next').removeClass("disabled")
|
||||
}
|
||||
|
||||
function unbindNavButtons() {
|
||||
$('#btn-band-setup-back').off("click")
|
||||
$('#btn-band-setup-cancel').off("click")
|
||||
$('#btn-band-setup-next').off("click")
|
||||
$('#btn-band-setup-back').addClass("disabled")
|
||||
$('#btn-band-setup-cancel').addClass("disabled")
|
||||
$('#btn-band-setup-next').addClass("disabled")
|
||||
}
|
||||
|
||||
function events() {
|
||||
$('#selected-band-invitees').on("click", ".invitation a", removeInvitation);
|
||||
|
||||
bindNavButtons();
|
||||
|
||||
// friend input focus
|
||||
$('#band-invitee-input').focus(function () {
|
||||
$(this).val('');
|
||||
});
|
||||
|
||||
$('#btn-band-setup-cancel').click(function () {
|
||||
resetForm();
|
||||
window.history.go(-1);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#btn-band-setup-next').click(function () {
|
||||
validateGeneralInfo()
|
||||
.done(function (response) {
|
||||
if (!step1 && !step2) {
|
||||
$("#band-setup-step-2").show();
|
||||
$("#band-setup-step-1").hide();
|
||||
} else if (step1) {
|
||||
saveBand();
|
||||
}
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
renderErrors(JSON.parse(jqXHR.responseText))
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(jqXHR, "Unable to validate band")
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#btn-band-setup-back').click(function () {
|
||||
if (!step2) {
|
||||
$("#band-setup-step-1").show();
|
||||
$("#band-setup-step-2").hide();
|
||||
} else {
|
||||
showProfile(bandId);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$('#btn-band-setup-save').click(saveBand);
|
||||
|
||||
$('#band-country').on('change', function (evt) {
|
||||
evt.stopPropagation();
|
||||
loadRegions();
|
||||
|
|
@ -519,7 +667,7 @@
|
|||
});
|
||||
|
||||
$('#band-change-photo').click(navigateToBandPhoto);
|
||||
$('#band-setup .avatar-profile').click(navigateToBandPhoto);
|
||||
$('#band-setup .band-avatar-profile').click(navigateToBandPhoto);
|
||||
|
||||
$('div[layout-id="band/setup"] .btn-email-invitation').click(function () {
|
||||
invitationDialog.showEmailDialog();
|
||||
|
|
@ -533,27 +681,57 @@
|
|||
invitationDialog.showFacebookDialog();
|
||||
});
|
||||
|
||||
$('a#choose-desired-experience').on("click", chooseExperience)
|
||||
|
||||
$('#band-setup').on('ifToggled', 'input[type="radio"].dependent-master', renderOptionalControls);
|
||||
|
||||
$(friendInput).focus(function() { $(this).val(''); })
|
||||
}
|
||||
|
||||
function chooseExperience(e) {
|
||||
e.stopPropagation()
|
||||
ui.launchInstrumentSelectorDialog("new member(s)", $selectedInstruments, function(selectedInstruments) {
|
||||
$selectedInstruments = selectedInstruments
|
||||
renderDesiredExperienceLabel($selectedInstruments)
|
||||
return false
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
function loadBandCallback() {
|
||||
return (isNewBand()) ? {} : rest.getBand(bandId)
|
||||
}
|
||||
|
||||
function initialize(invitationDialogInstance, friendSelectorDialog) {
|
||||
inviteMusiciansUtil = new JK.InviteMusiciansUtil(app);
|
||||
inviteMusiciansUtil.initialize(friendSelectorDialog);
|
||||
friendInput = inviteMusiciansUtil.inviteBandCreate('#band-setup-invite-musicians', "<div class='left w70'>If your bandmates are already on JamKazam, start typing their names in the box below, or click the Choose Friends button to select them.</div>");
|
||||
invitationDialog = invitationDialogInstance;
|
||||
events();
|
||||
inviteMusiciansUtil = new JK.InviteMusiciansUtil(app)
|
||||
inviteMusiciansUtil.initialize(friendSelectorDialog)
|
||||
|
||||
friendInput = inviteMusiciansUtil.inviteBandCreate('#band-setup-invite-musicians', "<div class='left w70'>If your bandmates are already on JamKazam, start typing their names in the box below, or click the Choose Friends button to select them.</div>")
|
||||
invitationDialog = invitationDialogInstance
|
||||
events()
|
||||
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
}
|
||||
|
||||
app.bindScreen('band/setup', screenBindings);
|
||||
bandType=$("#band-type")
|
||||
bandStatus=$("#band-status")
|
||||
concertCount=$("#concert-count")
|
||||
|
||||
app.bindScreen('band/setup', screenBindings)
|
||||
|
||||
$screen.find('input[type=radio]').iCheck({
|
||||
checkboxClass: 'icheckbox_minimal',
|
||||
radioClass: 'iradio_minimal',
|
||||
inheritClass: true
|
||||
})
|
||||
|
||||
profileUtils.initializeHelpBubbles()
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.afterShow = afterShow;
|
||||
return this;
|
||||
};
|
||||
|
||||
})(window, jQuery);
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.GenreSelectorDialog = function(app, type, genres, callback) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var $dialog = null;
|
||||
var dialogId = 'genre-selector-dialog';
|
||||
var $screen = $('#' + dialogId);
|
||||
var $btnSelect = $screen.find(".btn-select-genres");
|
||||
var $instructions = $screen.find('.instructions');
|
||||
var $genres = $screen.find('.genres');
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
var genreList = context.JK.genres;
|
||||
|
||||
$genres.empty();
|
||||
|
||||
if (genreList) {
|
||||
$.each(genreList, function(index, val) {
|
||||
$genres.append('<li>');
|
||||
var checked = '';
|
||||
if (genres && $.inArray(val.id, genres) > -1) {
|
||||
checked = 'checked';
|
||||
}
|
||||
|
||||
$genres.append('<input type="checkbox" value="' + val.id + '" ' + checked + ' />' + val.description);
|
||||
$genres.append('</li>');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
$btnSelect.unbind("click")
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
$btnSelect.unbind("click").bind("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
var selectedGenres = [];
|
||||
$genres.find('input[type=checkbox]:checked').each(function(index) {
|
||||
selectedGenres.push($(this).val());
|
||||
});
|
||||
|
||||
if (callback) {
|
||||
callback(selectedGenres);
|
||||
}
|
||||
|
||||
app.layout.closeDialog(dialogId);
|
||||
|
||||
return false;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$instructions.html('Select one or more genres for ' + type + ':');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
}
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.InstrumentSelectorDialog = function(app, type, instruments, callback) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var $dialog = null;
|
||||
var dialogId = 'instrument-selector-dialog';
|
||||
var $screen = $('#' + dialogId);
|
||||
var $btnSelect = $screen.find(".btn-select-instruments");
|
||||
var $instructions = $screen.find('.instructions');
|
||||
var $instruments = $screen.find('.instruments');
|
||||
var $instrumentSelectorContainer = $screen.find('.instrument-selector-container')
|
||||
var instrumentSelector = new JK.InstrumentSelector(app, $instrumentSelectorContainer);
|
||||
var $callback = callback
|
||||
var selectedInstruments = instruments
|
||||
function beforeShow(data) {
|
||||
instrumentSelector.initialize(false)
|
||||
instrumentSelector.render($instrumentSelectorContainer)
|
||||
instrumentSelector.setSelectedInstruments(selectedInstruments)
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
// var instrumentList = context.JK.instruments;
|
||||
|
||||
// $instruments.empty();
|
||||
|
||||
// if (instrumentList) {
|
||||
// $.each(instrumentList, function(index, val) {
|
||||
// $instruments.append('<li>');
|
||||
// var checked = '';
|
||||
// if (instruments && $.inArray(val.id, selectedInstruments) > -1) {
|
||||
// checked = 'checked';
|
||||
// }
|
||||
|
||||
// $instruments.append('<input type="checkbox" value="' + val.id + '" ' + checked + ' />' + val.description);
|
||||
// $instruments.append('</li>');
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
$btnSelect.unbind("click")
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
$btnSelect.unbind("click").bind("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
selectedInstruments = instrumentSelector.getSelectedInstruments()
|
||||
$callback(selectedInstruments)
|
||||
app.layout.closeDialog(dialogId);
|
||||
return false;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$instructions.html('Select the instruments and expertise you need for ' + type + ':');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
}
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.RecordingSelectorDialog = function(app, recordings, selectedRecordings, selectCallback) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var recordingUtils = context.JK.RecordingUtils;
|
||||
var $dialog = null;
|
||||
var dialogId = 'recording-selector-dialog';
|
||||
var $screen = $('#' + dialogId);
|
||||
var $btnSelect = $screen.find(".btn-select-recordings");
|
||||
var $instructions = $screen.find('#instructions');
|
||||
var $recordings = $screen.find('.recordings');
|
||||
var feedHelper = new context.JK.Feed(app);
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
|
||||
$recordings.empty();
|
||||
|
||||
$.each(recordings, function(index, val) {
|
||||
bindRecordingItem(val);
|
||||
});
|
||||
|
||||
// hide the avatars
|
||||
$screen.find('.avatar-small.ib').hide();
|
||||
}
|
||||
|
||||
/********* THE FOLLOWING BLOCK IS REPEATED IN feedHelper.js **********/
|
||||
function startRecordingPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
img.attr('src', '/assets/content/icon_pausebutton.png');
|
||||
$controls.trigger('play.listenRecording');
|
||||
$feedItem.data('playing', true);
|
||||
}
|
||||
|
||||
function stopRecordingPlay($feedItem) {
|
||||
var img = $('.play-icon', $feedItem);
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
img.attr('src', '/assets/content/icon_playbutton.png');
|
||||
$controls.trigger('pause.listenRecording');
|
||||
$feedItem.data('playing', false);
|
||||
}
|
||||
|
||||
function toggleRecordingPlay() {
|
||||
|
||||
var $playLink = $(this);
|
||||
var $feedItem = $playLink.closest('.feed-entry');
|
||||
var playing = $feedItem.data('playing');
|
||||
|
||||
if(playing) {
|
||||
stopRecordingPlay($feedItem);
|
||||
}
|
||||
else {
|
||||
startRecordingPlay($feedItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function toggleRecordingDetails() {
|
||||
var $detailsLink = $(this);
|
||||
var $feedItem = $detailsLink.closest('.feed-entry');
|
||||
var $musicians = $feedItem.find('.musician-detail');
|
||||
var $description = $feedItem.find('.description');
|
||||
var $name = $feedItem.find('.name');
|
||||
var toggledOpen = $detailsLink.data('toggledOpen');
|
||||
|
||||
if(toggledOpen) {
|
||||
toggleClose($feedItem, $name, $description, $musicians)
|
||||
}
|
||||
else {
|
||||
toggleOpen($feedItem, $name, $description, $musicians)
|
||||
}
|
||||
|
||||
toggledOpen = !toggledOpen;
|
||||
$detailsLink.data('toggledOpen', toggledOpen);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function stateChangeRecording(e, data) {
|
||||
var $controls = data.element;
|
||||
var $feedItem = $controls.closest('.feed-entry');
|
||||
|
||||
var $sliderBar = $('.recording-position', $feedItem);
|
||||
var $statusBar = $('.recording-status', $feedItem);
|
||||
var $currentTime = $('.recording-current', $feedItem);
|
||||
var $status = $('.status-text', $feedItem);
|
||||
var $playButton = $('.play-button', $feedItem);
|
||||
|
||||
if(data.isEnd) stopRecordingPlay($feedItem);
|
||||
if(data.isError) {
|
||||
$sliderBar.hide();
|
||||
$playButton.hide();
|
||||
$currentTime.hide();
|
||||
$statusBar.show();
|
||||
$status.text(data.displayText);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleOpen($feedItem, $name, $description, $musicians) {
|
||||
$description.trigger('destroy.dot');
|
||||
$description.data('original-height', $description.css('height')).css('height', 'auto');
|
||||
$name.trigger('destroy.dot');
|
||||
$name.data('original-height', $name.css('height')).css('height', 'auto');
|
||||
$musicians.show();
|
||||
$feedItem.animate({'max-height': '1000px'});
|
||||
}
|
||||
|
||||
function toggleClose($feedItem, $name, $description, $musicians, immediate) {
|
||||
$feedItem.css('height', $feedItem.height() + 'px')
|
||||
$feedItem.animate({'height': $feedItem.data('original-max-height')}, immediate ? 0 : 400).promise().done(function() {
|
||||
$feedItem.css('height', 'auto').css('max-height', $feedItem.data('original-max-height'));
|
||||
|
||||
$musicians.hide();
|
||||
$description.css('height', $description.data('original-height'));
|
||||
$description.dotdotdot();
|
||||
$name.css('height', $name.data('original-height'));
|
||||
$name.dotdotdot();
|
||||
});
|
||||
}
|
||||
/**********************************************************/
|
||||
|
||||
function bindRecordingItem(claimedRecording) {
|
||||
claimedRecording.recording.mix_info = recordingUtils.createMixInfo({state: claimedRecording.recording.mix_state});
|
||||
var options = {
|
||||
feed_item: claimedRecording.recording,
|
||||
candidate_claimed_recording: claimedRecording,
|
||||
mix_class: claimedRecording['has_mix?'] ? 'has-mix' : 'no-mix',
|
||||
};
|
||||
|
||||
var $feedItem = $(context._.template($('#template-feed-recording').html(), options, {variable: 'data'}));
|
||||
var $controls = $feedItem.find('.recording-controls');
|
||||
|
||||
var $titleText = $feedItem.find('.title .title-text');
|
||||
|
||||
// if this item will be discarded, tack on a * to the RECORDING NAME
|
||||
var discardTime = claimedRecording.recording['when_will_be_discarded?'];
|
||||
if(discardTime) {
|
||||
context.JK.helpBubble($titleText, 'recording-discarded-soon', {discardTime: discardTime}, {});
|
||||
$titleText.text($titleText.text() + '*');
|
||||
}
|
||||
|
||||
$controls.data('mix-state', claimedRecording.recording.mix_info); // for recordingUtils helper methods
|
||||
$controls.data('server-info', claimedRecording.recording.mix); // for recordingUtils helper methods
|
||||
$controls.data('view-context', 'feed');
|
||||
|
||||
$('.timeago', $feedItem).timeago();
|
||||
context.JK.prettyPrintElements($('.duration', $feedItem));
|
||||
context.JK.setInstrumentAssetPath($('.instrument-icon', $feedItem));
|
||||
$('.details', $feedItem).click(toggleRecordingDetails);
|
||||
$('.details-arrow', $feedItem).click(toggleRecordingDetails);
|
||||
$('.play-button', $feedItem).click(toggleRecordingPlay);
|
||||
|
||||
var checked = '';
|
||||
|
||||
var match = $.grep(selectedRecordings, function(obj, index) {
|
||||
return obj.claimed_recording_id === claimedRecording.id;
|
||||
});
|
||||
|
||||
if (match && match.length > 0) {
|
||||
checked = 'checked';
|
||||
}
|
||||
|
||||
// put the item on the page
|
||||
$recordings.append("<div class='left'><input type='checkbox' " + checked + " data-recording-id='" + claimedRecording.id + "' data-recording-title='" + claimedRecording.name + "' />");
|
||||
$recordings.append($feedItem);
|
||||
|
||||
// these routines need the item to have height to work (must be after renderFeed)
|
||||
$controls.listenRecording({recordingId: claimedRecording.recording.id, claimedRecordingId: options.candidate_claimed_recording.id, sliderSelector:'.recording-slider', sliderBarSelector: '.recording-playback', currentTimeSelector:'.recording-current'});
|
||||
$controls.bind('statechange.listenRecording', stateChangeRecording);
|
||||
$('.dotdotdot', $feedItem).dotdotdot();
|
||||
$feedItem.data('original-max-height', $feedItem.css('height'));
|
||||
context.JK.bindHoverEvents($feedItem);
|
||||
context.JK.bindProfileClickEvents($feedItem);
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
$btnSelect.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
var preSelectedRecordings = [];
|
||||
$recordings.find('input[type=checkbox]:checked').each(function(index) {
|
||||
preSelectedRecordings.push({
|
||||
"id": $(this).attr('data-recording-id'),
|
||||
"name": $(this).attr('data-recording-title')
|
||||
});
|
||||
});
|
||||
|
||||
if (selectCallback) {
|
||||
selectCallback(preSelectedRecordings);
|
||||
}
|
||||
|
||||
app.layout.closeDialog(dialogId);
|
||||
|
||||
return false;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$instructions.html('Select one or more recordings and click ADD to add JamKazam recordings to your performance samples.');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
}
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {}
|
||||
|
||||
context.JK.SoundCloudPlayerDialog = class SoundCloudPlayerDialog
|
||||
constructor: (@app) ->
|
||||
@rest = context.JK.Rest()
|
||||
@client = context.jamClient
|
||||
@logger = context.JK.logger
|
||||
@screen = null
|
||||
@dialogId = 'sound-cloud-player-dialog'
|
||||
@dialog = null
|
||||
@player = null
|
||||
|
||||
initialize:(@url, @caption) =>
|
||||
dialogBindings = {
|
||||
'beforeShow' : @beforeShow,
|
||||
'afterShow' : @afterShow
|
||||
}
|
||||
|
||||
@dialog = $('[layout-id="' + @dialogId + '"]')
|
||||
@app.bindDialog(@dialogId, dialogBindings)
|
||||
@player = @dialog.find(".sound-cloud-player")
|
||||
@dialog.find(".caption").text("'#{@caption}'")
|
||||
@player.addClass("hidden")
|
||||
|
||||
beforeShow:() =>
|
||||
@player.addClass("hidden")
|
||||
@player.attr("src", "")
|
||||
u = encodeURIComponent(@url)
|
||||
src = "https://w.soundcloud.com/player/?url=#{u}&auto_play=true&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true&loop=true"
|
||||
@player.attr("src", src)
|
||||
|
||||
afterShow:() =>
|
||||
@player.removeClass("hidden")
|
||||
|
||||
showDialog:() =>
|
||||
@app.layout.showDialog(@dialogId)
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
@ -242,7 +251,7 @@
|
|||
return candidate;
|
||||
}
|
||||
else {
|
||||
return recording.claimed_recordings[0]
|
||||
return recording.claimed_recordings[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -363,4 +363,4 @@
|
|||
"Metronome" : "Metronome"
|
||||
}
|
||||
|
||||
})(window,jQuery);
|
||||
})(window,jQuery);
|
||||
|
|
|
|||
|
|
@ -4,18 +4,19 @@
|
|||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.InstrumentSelectorDeferred = null;
|
||||
context.JK.InstrumentSelector = (function(app) {
|
||||
context.JK.InstrumentSelector = (function(app, parentSelector) {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
var rest = new context.JK.Rest();
|
||||
var _instruments = []; // will be list of structs: [ {label:xxx, value:yyy}, {...}, ... ]
|
||||
var _rsvp = false;
|
||||
var _parentSelector = null;
|
||||
if (typeof(_parentSelector)=="undefined") {_parentSelector=null}
|
||||
var _parentSelector = parentSelector;
|
||||
var deferredInstruments = null;
|
||||
var self = this;
|
||||
|
||||
function reset() {
|
||||
$('input[type=checkbox]', _parentSelector).attr('checked', '');
|
||||
$('input[type="checkbox"]', _parentSelector).attr('checked', '');
|
||||
if (_rsvp) {
|
||||
$('select.rsvp_count option', _parentSelector).eq(0).prop('selected', true);
|
||||
$('select.rsvp_level option', _parentSelector).eq(0).prop('selected', true);
|
||||
|
|
@ -88,7 +89,7 @@
|
|||
var $selectedVal = $('input[type="checkbox"]:checked', _parentSelector);
|
||||
$.each($selectedVal, function (index, value) {
|
||||
var id = $(value).attr('session-instrument-id');
|
||||
var name = $('label[for="' + $(value).attr('id') + '"]', _parentSelector).text();
|
||||
var name = $('label[for="' + $(value).attr('id') + '"]', _parentSelector).text().trim();
|
||||
if (_rsvp) {
|
||||
var count = $('select[session-instrument-id="' + id + '"].rsvp-count', _parentSelector).val();
|
||||
var rsvp_level = $('select[session-instrument-id="' + id + '"].rsvp-level', _parentSelector).val();
|
||||
|
|
@ -99,16 +100,16 @@
|
|||
selectedInstruments.push({id: id, name: name, level: level});
|
||||
}
|
||||
});
|
||||
|
||||
return selectedInstruments;
|
||||
}
|
||||
|
||||
function setSelectedInstruments(instrumentList) {
|
||||
if (!instrumentList) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.each(instrumentList, function (index, value) {
|
||||
$('input[type=checkbox][id="' + value.id + '"]')
|
||||
}
|
||||
$.each(instrumentList, function (index, value) {
|
||||
$('input[type="checkbox"][session-instrument-id="' + value.id + '"]')
|
||||
.attr('checked', 'checked')
|
||||
.iCheck({
|
||||
checkboxClass: 'icheckbox_minimal',
|
||||
|
|
@ -116,11 +117,11 @@
|
|||
inheritClass: true
|
||||
});
|
||||
if (_rsvp) {
|
||||
$('select[session-instrument-id="' + value.value + '"].rsvp-count', _parentSelector).val(value.count);
|
||||
$('select[session-instrument-id="' + value.value + '"].rsvp-level', _parentSelector).val(value.level);
|
||||
$('select[session-instrument-id="' + value.id + '"].rsvp-count', _parentSelector).val(value.count);
|
||||
$('select[session-instrument-id="' + value.id + '"].rsvp-level', _parentSelector).val(value.level);
|
||||
}
|
||||
else {
|
||||
$('select[session-instrument-id="' + value.value + '"]').val(value.level);
|
||||
$('select[session-instrument-id="' + value.id + '"]').val(value.level);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@
|
|||
if (includePending) {
|
||||
includeFlag = 'true';
|
||||
}
|
||||
|
||||
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
|
|
@ -521,6 +521,20 @@
|
|||
return detail;
|
||||
}
|
||||
|
||||
function getUserProfile(options) {
|
||||
var id = getId(options);
|
||||
var profile = null;
|
||||
if (id != null && typeof(id) != 'undefined') {
|
||||
profile = $.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
url: "/api/users/" + id + "/profile",
|
||||
processData: false
|
||||
});
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
function createAffiliatePartner(options) {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
|
|
@ -1289,7 +1303,7 @@
|
|||
function openBackingTrack(options) {
|
||||
var musicSessionId = options["id"];
|
||||
delete options["id"];
|
||||
|
||||
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
|
|
@ -1352,7 +1366,7 @@
|
|||
function openMetronome(options) {
|
||||
var musicSessionId = options["id"];
|
||||
delete options["id"];
|
||||
|
||||
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
|
|
@ -1361,11 +1375,11 @@
|
|||
data: JSON.stringify(options)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function closeMetronome(options) {
|
||||
var musicSessionId = options["id"];
|
||||
delete options["id"];
|
||||
|
||||
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
|
|
@ -1374,7 +1388,7 @@
|
|||
data: JSON.stringify(options)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function discardRecording(options) {
|
||||
var recordingId = options["id"];
|
||||
|
||||
|
|
@ -1613,7 +1627,7 @@
|
|||
url: '/api/recurly/payment_history',
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getSalesHistory(options) {
|
||||
|
|
@ -1709,7 +1723,7 @@
|
|||
|
||||
function placeOrder() {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
type: "POST",
|
||||
url: '/api/recurly/place_order',
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
|
|
@ -1723,6 +1737,19 @@
|
|||
});
|
||||
}
|
||||
|
||||
function getMusicianSearchFilter(query) {
|
||||
var qarg = query === undefined ? '' : query;
|
||||
return $.get("/api/search/musicians.json?"+qarg);
|
||||
}
|
||||
|
||||
function postMusicianSearchFilter(query) {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: "/api/search/musicians.json",
|
||||
data: query
|
||||
});
|
||||
}
|
||||
|
||||
function getMount(options) {
|
||||
var id = getId(options);
|
||||
return $.ajax({
|
||||
|
|
@ -1824,6 +1851,7 @@
|
|||
this.cancelSession = cancelSession;
|
||||
this.updateScheduledSession = updateScheduledSession;
|
||||
this.getUserDetail = getUserDetail;
|
||||
this.getUserProfile = getUserProfile;
|
||||
this.getAffiliatePartnerData = getAffiliatePartnerData;
|
||||
this.postAffiliatePartnerData = postAffiliatePartnerData;
|
||||
this.createAffiliatePartner = createAffiliatePartner;
|
||||
|
|
@ -1907,7 +1935,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;
|
||||
|
|
@ -1965,6 +1993,8 @@
|
|||
this.validateUrlSite = validateUrlSite;
|
||||
this.markRecordedBackingTrackSilent = markRecordedBackingTrackSilent;
|
||||
this.addRecordingTimeline = addRecordingTimeline;
|
||||
this.getMusicianSearchFilter = getMusicianSearchFilter;
|
||||
this.postMusicianSearchFilter = postMusicianSearchFilter;
|
||||
this.playJamTrack = playJamTrack;
|
||||
this.createSignupHint = createSignupHint;
|
||||
this.createAlert = createAlert;
|
||||
|
|
@ -1972,5 +2002,4 @@
|
|||
this.portOverCarts = portOverCarts;
|
||||
return this;
|
||||
};
|
||||
|
||||
})(window,jQuery);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,417 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {};
|
||||
|
||||
context.JK.MusicianSearchFilter = class MusicianSearchFilter
|
||||
|
||||
constructor: () ->
|
||||
@rest = context.JK.Rest()
|
||||
@logger = context.JK.logger
|
||||
@searchFilter = null
|
||||
@profileUtils = context.JK.ProfileUtils
|
||||
@helpBubble = context.JK.HelpBubbleHelper
|
||||
@searchResults = null
|
||||
@isSearching = false
|
||||
@pageNumber = 1
|
||||
@instrument_logo_map = context.JK.getInstrumentIconMap24()
|
||||
|
||||
init: (app) =>
|
||||
@app = app
|
||||
@screenBindings = { 'afterShow': this.afterShow, 'afterHide': this.afterHide }
|
||||
@app.bindScreen('musicians', @screenBindings)
|
||||
|
||||
@screen = $('#musicians-screen')
|
||||
@resultsListContainer = @screen.find('#musician-search-filter-results-list')
|
||||
@spinner = @screen.find('.paginate-wait')
|
||||
|
||||
this.registerResultsPagination()
|
||||
|
||||
@screen.find('#btn-musician-search-builder').on 'click', =>
|
||||
this.showBuilder()
|
||||
|
||||
@screen.find('#btn-musician-search-reset').on 'click', =>
|
||||
this.resetFilter()
|
||||
|
||||
afterShow: () =>
|
||||
@screen.find('#musician-search-filter-results').show()
|
||||
@screen.find('#musician-search-filter-builder').hide()
|
||||
this.getUserFilterResults()
|
||||
|
||||
showBuilder: () =>
|
||||
@screen.find('#musician-search-filter-results').hide()
|
||||
@screen.find('#musician-search-filter-builder').show()
|
||||
@resultsListContainer.empty()
|
||||
|
||||
afterHide: () =>
|
||||
@resultsListContainer.empty()
|
||||
|
||||
renderSearchFilter: () =>
|
||||
$.when(this.rest.getMusicianSearchFilter()).done (sFilter) =>
|
||||
this.loadSearchFilter(sFilter)
|
||||
|
||||
loadSearchFilter: (sFilter) =>
|
||||
@searchFilter = JSON.parse(sFilter)
|
||||
args =
|
||||
interests: @searchFilter.data_blob.interests
|
||||
skill_level: @searchFilter.data_blob.skill_level
|
||||
studio_sessions: @searchFilter.data_blob.studio_sessions
|
||||
concert_gigs: @searchFilter.data_blob.concert_gigs
|
||||
|
||||
template = context.JK.fillTemplate(@screen.find('#template-musician-search-filter').html(), args)
|
||||
|
||||
content_root = @screen.find('#musician-search-filter-builder')
|
||||
content_root.html template
|
||||
|
||||
@screen.find('#btn-perform-musician-search').on 'click', =>
|
||||
this.performSearch()
|
||||
|
||||
@screen.find('#btn-musician-search-cancel').on 'click', =>
|
||||
this.cancelFilter()
|
||||
|
||||
this._populateSkill()
|
||||
this._populateStudio()
|
||||
this._populateGigs()
|
||||
this._populateInterests()
|
||||
this._populateAges()
|
||||
this._populateGenres()
|
||||
this._populateInstruments()
|
||||
this._populateSortOrder()
|
||||
|
||||
|
||||
|
||||
_populateSelectWithKeys: (struct, selection, keys, element) =>
|
||||
element.children().remove()
|
||||
$.each keys, (idx, value) =>
|
||||
label = struct[value]
|
||||
blankOption = $ '<option value=""></option>'
|
||||
blankOption.text label
|
||||
blankOption.attr 'value', value
|
||||
blankOption.attr 'selected', '' if value == selection
|
||||
element.append(blankOption)
|
||||
context.JK.dropdown(element)
|
||||
|
||||
_populateSelectIdentifier: (identifier) =>
|
||||
elem = $ '#musician-search-filter-builder select[name='+identifier+']'
|
||||
struct = gon.musician_search_meta[identifier]['map']
|
||||
keys = gon.musician_search_meta[identifier]['keys']
|
||||
this._populateSelectWithKeys(struct, @searchFilter[identifier], keys, elem)
|
||||
|
||||
_populateSelectWithInt: (sourceStruct, selection, element) =>
|
||||
struct =
|
||||
'-1': 'Any'
|
||||
$.extend(struct, sourceStruct)
|
||||
this._populateSelectWithKeys(struct, selection, Object.keys(struct).sort(), element)
|
||||
|
||||
_populateSortOrder: () =>
|
||||
this._populateSelectIdentifier('sort_order')
|
||||
|
||||
_populateInterests: () =>
|
||||
this._populateSelectIdentifier('interests')
|
||||
|
||||
_populateStudio: () =>
|
||||
elem = $ '#musician-search-filter-builder select[name=studio_sessions]'
|
||||
this._populateSelectWithInt(@profileUtils.studioMap, @searchFilter.data_blob.studio_sessions.toString(), elem)
|
||||
|
||||
_populateGigs: () =>
|
||||
elem = $ '#musician-search-filter-builder select[name=concert_gigs]'
|
||||
this._populateSelectWithInt(@profileUtils.gigMap, @searchFilter.data_blob.concert_gigs.toString(), elem)
|
||||
|
||||
_populateSkill: () =>
|
||||
elem = $ '#musician-search-filter-builder select[name=skill_level]'
|
||||
this._populateSelectWithInt(@profileUtils.skillLevelMap, @searchFilter.data_blob.skill_level.toString(), elem)
|
||||
|
||||
_populateAges: () =>
|
||||
@screen.find('#search-filter-ages').empty()
|
||||
ages_map = gon.musician_search_meta['ages']['map']
|
||||
$.each gon.musician_search_meta['ages']['keys'], (index, key) =>
|
||||
ageTemplate = @screen.find('#template-search-filter-setup-ages').html()
|
||||
selected = ''
|
||||
ageLabel = ages_map[key]
|
||||
if 0 < @searchFilter.data_blob.ages.length
|
||||
key_val = key.toString()
|
||||
ageMatch = $.grep(@searchFilter.data_blob.ages, (n, i) ->
|
||||
n == key_val)
|
||||
selected = 'checked' if ageMatch.length > 0
|
||||
ageHtml = context.JK.fillTemplate(ageTemplate,
|
||||
id: key
|
||||
description: ageLabel
|
||||
checked: selected)
|
||||
@screen.find('#search-filter-ages').append ageHtml
|
||||
|
||||
_populateGenres: () =>
|
||||
@screen.find('#search-filter-genres').empty()
|
||||
@rest.getGenres().done (genres) =>
|
||||
genreTemplate = @screen.find('#template-search-filter-setup-genres').html()
|
||||
selected = ''
|
||||
$.each genres, (index, genre) =>
|
||||
if 0 < @searchFilter.data_blob.genres.length
|
||||
genreMatch = $.grep(@searchFilter.data_blob.genres, (n, i) ->
|
||||
n == genre.id)
|
||||
else
|
||||
genreMatch = []
|
||||
selected = 'checked' if genreMatch.length > 0
|
||||
genreHtml = context.JK.fillTemplate(genreTemplate,
|
||||
id: genre.id
|
||||
description: genre.description
|
||||
checked: selected)
|
||||
@screen.find('#search-filter-genres').append genreHtml
|
||||
|
||||
_populateInstruments: () =>
|
||||
@screen.find('#search-filter-instruments').empty()
|
||||
@rest.getInstruments().done (instruments) =>
|
||||
$.each instruments, (index, instrument) =>
|
||||
instrumentTemplate = @screen.find('#template-search-filter-setup-instrument').html()
|
||||
selected = ''
|
||||
proficiency = '1'
|
||||
if 0 < @searchFilter.data_blob.instruments.length
|
||||
instMatch = $.grep(@searchFilter.data_blob.instruments, (inst, i) ->
|
||||
yn = inst.instrument_id == instrument.id
|
||||
proficiency = inst.proficiency_level if yn
|
||||
yn)
|
||||
selected = 'checked' if instMatch.length > 0
|
||||
instrumentHtml = context.JK.fillTemplate(instrumentTemplate,
|
||||
id: instrument.id
|
||||
description: instrument.description
|
||||
checked: selected)
|
||||
@screen.find('#search-filter-instruments').append instrumentHtml
|
||||
profsel = '#search-filter-instruments tr[data-instrument-id="'+instrument.id+'"] select'
|
||||
jprofsel = @screen.find(profsel)
|
||||
jprofsel.val(proficiency)
|
||||
context.JK.dropdown(jprofsel)
|
||||
return true
|
||||
|
||||
_builderSelectValue: (identifier) =>
|
||||
elem = $ '#musician-search-filter-builder select[name='+identifier+']'
|
||||
elem.val()
|
||||
|
||||
_builderSelectMultiValue: (identifier) =>
|
||||
vals = []
|
||||
elem = $ '#search-filter-'+identifier+' input[type=checkbox]:checked'
|
||||
if 'instruments' == identifier
|
||||
elem.each (idx) ->
|
||||
row = $(this).parent().parent()
|
||||
instrument =
|
||||
instrument_id: row.data('instrument-id')
|
||||
proficiency_level: row.find('select').val()
|
||||
vals.push instrument
|
||||
else
|
||||
elem.each (idx) ->
|
||||
vals.push $(this).val()
|
||||
vals
|
||||
|
||||
willSearch: (reload) =>
|
||||
return false if @isSearching
|
||||
@isSearching = true
|
||||
if reload
|
||||
@pageNumber = 1
|
||||
@screen.find('#musician-search-filter-spinner').show()
|
||||
@resultsListContainer.empty()
|
||||
@screen.find('#musician-search-filter-builder').hide()
|
||||
@screen.find('#musician-search-filter-results').show()
|
||||
true
|
||||
|
||||
didSearch: (response) =>
|
||||
this.loadSearchFilter(response.filter_json)
|
||||
@searchResults = response
|
||||
@screen.find('#musician-search-filter-spinner').hide()
|
||||
this.renderMusicians()
|
||||
@screen.find('.paginate-wait').hide()
|
||||
@isSearching = false
|
||||
|
||||
resetFilter: () =>
|
||||
if this.willSearch(true)
|
||||
@rest.postMusicianSearchFilter({ filter: 'reset' }).done(this.didSearch)
|
||||
|
||||
cancelFilter: () =>
|
||||
this.resetFilter()
|
||||
|
||||
getUserFilterResults: () =>
|
||||
if this.willSearch(true)
|
||||
@rest.getMusicianSearchFilter('results=true').done(this.didSearch)
|
||||
|
||||
performSearch: () =>
|
||||
if this.willSearch(true)
|
||||
$.each gon.musician_search_meta.filter_keys.single, (index, key) =>
|
||||
@searchFilter[key] = this._builderSelectValue(key)
|
||||
$.each gon.musician_search_meta.filter_keys.multi, (index, key) =>
|
||||
@searchFilter[key] = this._builderSelectMultiValue(key)
|
||||
@rest.postMusicianSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch)
|
||||
|
||||
renderResultsHeader: () =>
|
||||
@screen.find('#musician-search-filter-description').html(@searchResults.description)
|
||||
if @searchResults.is_blank_filter
|
||||
@screen.find('#btn-musician-search-reset').hide()
|
||||
else
|
||||
@screen.find('#btn-musician-search-reset').show()
|
||||
|
||||
renderMusicians: () =>
|
||||
this.renderResultsHeader() if @pageNumber == 1
|
||||
musicians = @searchResults.musicians
|
||||
len = musicians.length
|
||||
if 0 == len
|
||||
@screen.find('#musician-search-filter-results-list-blank').show()
|
||||
@screen.find('#musician-search-filter-results-list-blank').html('No results found')
|
||||
return
|
||||
else
|
||||
@screen.find('#musician-search-filter-results-list-blank').hide()
|
||||
|
||||
ii = 0
|
||||
mTemplate = @screen.find('#template-search-musician-row').html()
|
||||
aTemplate = @screen.find('#template-search-musician-action-btns').html()
|
||||
mVals = undefined
|
||||
musician = undefined
|
||||
renderings = ''
|
||||
instr_logos = undefined
|
||||
follows = undefined
|
||||
followVals = undefined
|
||||
aFollow = undefined
|
||||
myAudioLatency = @searchResults.my_audio_latency
|
||||
while ii < len
|
||||
musician = musicians[ii]
|
||||
if context.JK.currentUserId == musician.id
|
||||
ii++
|
||||
continue
|
||||
instr_logos = ''
|
||||
jj = 0
|
||||
ilen = musician['instruments'].length
|
||||
while jj < ilen
|
||||
instr_id = musician['instruments'][jj].instrument_id
|
||||
if instr_img = @instrument_logo_map[instr_id]
|
||||
instr_logos += '<img height="24" width="24" src="' + instr_img.asset + '" title="' + instr_id + '"/>'
|
||||
jj++
|
||||
actionVals =
|
||||
profile_url: '/client#/profile/' + musician.id
|
||||
friend_class: 'button-' + (if musician['is_friend'] then 'grey' else 'orange')
|
||||
friend_caption: (if musician.is_friend then 'DIS' else '') + 'CONNECT'
|
||||
follow_class: 'button-' + (if musician['is_following'] then 'grey' else 'orange')
|
||||
follow_caption: (if musician.is_following then 'UN' else '') + 'FOLLOW'
|
||||
message_class: 'button-orange'
|
||||
message_caption: 'MESSAGE'
|
||||
button_message: 'button-orange'
|
||||
musician_actions = context.JK.fillTemplate(aTemplate, actionVals)
|
||||
latencyBadge = context._.template($("#template-account-session-latency").html(), $.extend(sessionUtils.createLatency(musician), musician), variable: 'data')
|
||||
mVals =
|
||||
avatar_url: context.JK.resolveAvatarUrl(musician.photo_url)
|
||||
profile_url: '/client#/profile/' + musician.id
|
||||
musician_name: musician.name
|
||||
musician_location: this._formatLocation(musician)
|
||||
instruments: instr_logos
|
||||
biography: musician['biography']
|
||||
follow_count: musician['follow_count']
|
||||
friend_count: musician['friend_count']
|
||||
recording_count: musician['recording_count']
|
||||
session_count: musician['session_count']
|
||||
musician_id: musician['id']
|
||||
musician_action_template: musician_actions
|
||||
latency_badge: latencyBadge
|
||||
musician_first_name: musician['first_name']
|
||||
$rendering = $(context.JK.fillTemplate(mTemplate, mVals))
|
||||
$offsetParent = @resultsListContainer.closest('.content')
|
||||
data = entity_type: 'musician'
|
||||
options =
|
||||
positions: [
|
||||
'top'
|
||||
'bottom'
|
||||
'right'
|
||||
'left'
|
||||
]
|
||||
offsetParent: $offsetParent
|
||||
scoreOptions = offsetParent: $offsetParent
|
||||
context.JK.helpBubble($('.follower-count', $rendering), 'follower-count', data, options);
|
||||
context.JK.helpBubble($('.friend-count', $rendering), 'friend-count', data, options);
|
||||
context.JK.helpBubble($('.recording-count', $rendering), 'recording-count', data, options);
|
||||
context.JK.helpBubble($('.session-count', $rendering), 'session-count', data, options);
|
||||
@helpBubble.scoreBreakdown $('.latency', $rendering), false, musician['full_score'], myAudioLatency, musician['audio_latency'], musician['score'], scoreOptions
|
||||
@resultsListContainer.append $rendering
|
||||
$rendering.find('.biography').dotdotdot()
|
||||
ii++
|
||||
|
||||
this._bindMessageMusician()
|
||||
this._bindFriendMusician()
|
||||
this._bindFollowMusician()
|
||||
|
||||
context.JK.bindHoverEvents()
|
||||
return
|
||||
|
||||
_bindMessageMusician: () =>
|
||||
objThis = this
|
||||
@screen.find('.search-m-message').on 'click', (evt) ->
|
||||
userId = $(this).parent().data('musician-id')
|
||||
objThis.app.layout.showDialog 'text-message', d1: userId
|
||||
|
||||
|
||||
_bindFriendMusician: () =>
|
||||
objThis = this
|
||||
@screen.find('.search-m-friend').on 'click', (evt) ->
|
||||
# if the musician is already a friend, remove the button-orange class, and prevent the link from working
|
||||
if 0 == $(this).closest('.button-orange').size()
|
||||
return false
|
||||
$(this).click (ee) ->
|
||||
ee.preventDefault()
|
||||
return
|
||||
evt.stopPropagation()
|
||||
uid = $(this).parent().data('musician-id')
|
||||
objThis.rest.sendFriendRequest objThis.app, uid, this.friendRequestCallback
|
||||
|
||||
_bindFollowMusician: () =>
|
||||
objThis = this
|
||||
@screen.find('.search-m-follow').on 'click', (evt) ->
|
||||
# if the musician is already followed, remove the button-orange class, and prevent the link from working
|
||||
if 0 == $(this).closest('.button-orange').size()
|
||||
return false
|
||||
$(this).click (ee) ->
|
||||
ee.preventDefault()
|
||||
return
|
||||
evt.stopPropagation()
|
||||
newFollowing = {}
|
||||
newFollowing.user_id = $(this).parent().data('musician-id')
|
||||
url = '/api/users/' + context.JK.currentUserId + '/followings'
|
||||
$.ajax
|
||||
type: 'POST'
|
||||
dataType: 'json'
|
||||
contentType: 'application/json'
|
||||
url: url
|
||||
data: JSON.stringify(newFollowing)
|
||||
processData: false
|
||||
success: (response) ->
|
||||
# remove the orange look to indicate it's not selectable
|
||||
# @FIXME -- this will need to be tweaked when we allow unfollowing
|
||||
objThis.screen.find('div[data-musician-id=' + newFollowing.user_id + '] .search-m-follow').removeClass('button-orange').addClass 'button-grey'
|
||||
return
|
||||
error: objThis.app.ajaxError
|
||||
|
||||
_formatLocation: (musician) ->
|
||||
if musician.city and musician.state
|
||||
musician.city + ', ' + musician.state
|
||||
else if musician.city
|
||||
musician.city
|
||||
else if musician.regionname
|
||||
musician.regionname
|
||||
else
|
||||
'Location Unavailable'
|
||||
|
||||
friendRequestCallback: (user_id)=>
|
||||
# TODO:
|
||||
|
||||
paginate: () =>
|
||||
if @pageNumber < @searchResults.page_count && this.willSearch(false)
|
||||
@screen.find('.paginate-wait').show()
|
||||
@pageNumber += 1
|
||||
@rest.postMusicianSearchFilter({ filter: JSON.stringify(@searchFilter), page: @pageNumber }).done(this.didSearch)
|
||||
return true
|
||||
false
|
||||
|
||||
registerResultsPagination: () =>
|
||||
_resultsListContainer = @resultsListContainer
|
||||
_headerHeight = @screen.find('#musician-search-filter-results-header').height()
|
||||
_paginator = this.paginate
|
||||
|
||||
@screen.find('.content-body-scroller').scroll ->
|
||||
if _resultsListContainer.is(':visible')
|
||||
jthis = $(this)
|
||||
wintop = jthis.scrollTop()
|
||||
winheight = jthis.innerHeight()
|
||||
docheight = jthis[0].scrollHeight - _headerHeight
|
||||
scrollTrigger = 0.98;
|
||||
if ((wintop / (docheight - winheight)) >= scrollTrigger)
|
||||
_paginator()
|
||||
|
|
@ -11,24 +11,107 @@
|
|||
var rest = context.JK.Rest();
|
||||
var decrementedFriendCountOnce = false;
|
||||
var sentFriendRequest = false;
|
||||
var profileScreen = null;
|
||||
var textMessageDialog = null;
|
||||
var feed = null;
|
||||
var player = null;
|
||||
var profileUtils = context.JK.ProfileUtils;
|
||||
|
||||
var NOT_SPECIFIED_TEXT = 'Not specified';
|
||||
|
||||
var $screen = $('#user-profile');
|
||||
|
||||
var $biography = $screen.find('#biography');
|
||||
|
||||
// musical experience
|
||||
var $instruments = $screen.find('#instruments');
|
||||
var $musicianStatus = $screen.find('#musician-status');
|
||||
var $genres = $screen.find('#genres');
|
||||
var $concertCount = $screen.find('#concert-count');
|
||||
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');
|
||||
|
||||
// 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');
|
||||
|
||||
// current interests
|
||||
var $noInterests = $screen.find('#no-interests');
|
||||
var $paidGigSection = $screen.find('#paid-gigs');
|
||||
var $paidGigDetails = $screen.find('#paid-gig-details');
|
||||
|
||||
var $freeGigSection = $screen.find('#free-gigs');
|
||||
var $freeGigDetails = $screen.find('#free-gig-details');
|
||||
|
||||
var $cowritingSection = $screen.find('#cowriting');
|
||||
var $cowritingDetails = $screen.find('#cowriting-details');
|
||||
|
||||
var $traditionalBandSection = $screen.find('#traditional-band');
|
||||
var $traditionalBandDetails = $screen.find('#traditional-band-details');
|
||||
|
||||
var $virtualBandSection = $screen.find('#virtual-band');
|
||||
var $virtualBandDetails = $screen.find('#virtual-band-details');
|
||||
|
||||
// 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');
|
||||
|
||||
// stats
|
||||
var $friendStats = $screen.find('#friend-stats');
|
||||
var $followerStats = $screen.find('#follower-stats');
|
||||
var $sessionStats = $screen.find('#session-stats');
|
||||
var $recordingStats = $screen.find('#recording-stats');
|
||||
var $followingStats = $screen.find('#following-stats');
|
||||
var $favoriteStats = $screen.find('#favorite-stats');
|
||||
|
||||
// miscellaneous
|
||||
var $userName = $screen.find('#username');
|
||||
var $avatar = $screen.find('#avatar');
|
||||
var $typeLabel = $screen.find('#type-label');
|
||||
var $location = $screen.find('#location');
|
||||
var $age = $screen.find('#age');
|
||||
|
||||
// buttons
|
||||
var $btnEdit = $screen.find('#btn-edit');
|
||||
var $btnAddFriend = $screen.find('#btn-add-friend');
|
||||
var $btnFollowUser = $screen.find('#btn-follow-user');
|
||||
var $btnMessageUser = $screen.find('#btn-message-user');
|
||||
var $btnEditBio = $screen.find(".add-bio");
|
||||
var $btnAddRecordings = $screen.find('.add-recordings');
|
||||
var $btnAddSites = $screen.find('.add-sites');
|
||||
var $btnAddInterests = $screen.find('.add-interests');
|
||||
|
||||
// social
|
||||
var $socialLeft = $screen.find('.profile-social-left');
|
||||
var $socialFriends = $screen.find('#social-friends');
|
||||
var $socialFollowings = $screen.find('#social-followings');
|
||||
var $socialFollowers = $screen.find('#social-followers');
|
||||
|
||||
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);
|
||||
|
|
@ -37,6 +120,7 @@
|
|||
function afterShow(data) {
|
||||
initUser();
|
||||
resetForm();
|
||||
renderAllStats();
|
||||
}
|
||||
|
||||
function beforeHide(data) {
|
||||
|
|
@ -44,27 +128,28 @@
|
|||
}
|
||||
|
||||
function resetForm() {
|
||||
$('#profile-instruments').empty();
|
||||
$instruments.empty();
|
||||
|
||||
$('#profile-about').show();
|
||||
$('#profile-history').hide();
|
||||
$('#profile-bands').hide();
|
||||
$('#profile-social').hide();
|
||||
$('#profile-favorites').hide();
|
||||
$aboutContent.show();
|
||||
$historyContent.hide();
|
||||
$bandsContent.hide();
|
||||
$socialContent.hide();
|
||||
$favoritesContent.hide();
|
||||
|
||||
$('.profile-nav a.active').removeClass('active');
|
||||
$('.profile-nav a#profile-about-link').addClass('active');
|
||||
$aboutLink.addClass('active');
|
||||
}
|
||||
|
||||
function initUser() {
|
||||
user = null;
|
||||
decrementedFriendCountOnce = false;
|
||||
sentFriendRequest = false;
|
||||
userDefer = rest.getUserDetail({id: userId})
|
||||
userDefer = rest.getUserProfile({id: userId})
|
||||
.done(function (response) {
|
||||
user = response;
|
||||
configureUserType();
|
||||
renderActive();
|
||||
renderAllStats();
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
if (jqXHR.status >= 500) {
|
||||
|
|
@ -89,43 +174,41 @@
|
|||
|
||||
function configureUserType() {
|
||||
if (isMusician()) {
|
||||
$('#profile-history-link').show();
|
||||
$('#profile-bands-link').show();
|
||||
$('#profile-instruments').show();
|
||||
$('#profile-session-stats').show();
|
||||
$('#profile-recording-stats').show();
|
||||
// $('#profile-following-stats').hide();
|
||||
// $('#profile-favorites-stats').hide();
|
||||
$('.profile-social-left').show();
|
||||
$('#profile-type-label').text('musician');
|
||||
$('#profile-location-label').text('Location');
|
||||
}
|
||||
else {
|
||||
$('#profile-history-link').hide();
|
||||
$('#profile-bands-link').hide();
|
||||
$('#profile-instruments').hide();
|
||||
$('#profile-session-stats').hide();
|
||||
$('#profile-recording-stats').hide();
|
||||
// $('#profile-following-stats').show();
|
||||
// $('#profile-favorites-stats').show();
|
||||
$('.profile-social-left').hide();
|
||||
$('#profile-type-label').text('fan');
|
||||
$('#profile-location-label').text('Presence');
|
||||
$historyLink.show();
|
||||
$bandsLink.show();
|
||||
$instruments.show();
|
||||
$sessionStats.show();
|
||||
$recordingStats.show();
|
||||
// $followingStats.hide();
|
||||
// $favoriteStats.hide();
|
||||
$socialLeft.show();
|
||||
$typeLabel.text('musician');
|
||||
$location.text('Location');
|
||||
} else {
|
||||
$historyLink.hide();
|
||||
$bandsLink.hide();
|
||||
$instruments.hide();
|
||||
$sessionStats.hide();
|
||||
$recordingStats.hide();
|
||||
// $followingStats.show();
|
||||
// $favoriteStats.show();
|
||||
$socialLeft.hide();
|
||||
$typeLabel.text('fan');
|
||||
$location.text('Presence');
|
||||
}
|
||||
|
||||
if (isCurrentUser()) {
|
||||
$('#btn-profile-edit').show();
|
||||
$('#btn-add-friend').hide();
|
||||
$('#btn-follow-user').hide();
|
||||
$('#btn-message-user').hide();
|
||||
}
|
||||
else {
|
||||
$btnEdit.show();
|
||||
$btnAddFriend.hide();
|
||||
$btnFollowUser.hide();
|
||||
$btnMessageUser.hide();
|
||||
} else {
|
||||
configureFriendFollowersControls();
|
||||
|
||||
$('#btn-profile-edit').hide();
|
||||
$('#btn-add-friend').show();
|
||||
$('#btn-follow-user').show();
|
||||
$('#btn-message-user').show();
|
||||
$btnEdit.hide();
|
||||
$btnAddFriend.show();
|
||||
$btnFollowUser.show();
|
||||
$btnMessageUser.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,33 +224,48 @@
|
|||
// events for main screen
|
||||
function events() {
|
||||
// wire up panel clicks -- these need to check deferred because they can't be hidden when in an invalid state
|
||||
$('#profile-about-link').click(function () {
|
||||
$aboutLink.click(function () {
|
||||
renderTabDeferred(renderAbout)
|
||||
});
|
||||
$('#profile-history-link').click(function () {
|
||||
|
||||
$historyLink.click(function () {
|
||||
renderTabDeferred(renderHistory)
|
||||
});
|
||||
$('#profile-bands-link').click(function () {
|
||||
|
||||
$bandsLink.click(function () {
|
||||
renderTabDeferred(renderBands)
|
||||
});
|
||||
$('#profile-social-link').click(function () {
|
||||
|
||||
$socialLink.click(function () {
|
||||
renderTabDeferred(renderSocial)
|
||||
});
|
||||
$('#profile-favorites-link').click(function () {
|
||||
|
||||
$favoritesLink.click(function () {
|
||||
renderTabDeferred(renderFavorites)
|
||||
});
|
||||
|
||||
// this doesn't need deferred because it's only shown when valid
|
||||
$('#btn-add-friend').click(handleFriendChange);
|
||||
$('#btn-follow-user').click(handleFollowingChange);
|
||||
$('#btn-message-user').click(handleMessageMusician);
|
||||
$btnAddFriend.click(handleFriendChange);
|
||||
$btnFollowUser.click(handleFollowingChange);
|
||||
$btnMessageUser.click(handleMessageMusician);
|
||||
|
||||
// Hook up soundcloud player:
|
||||
$soundCloudSamples.off("click", "a.sound-cloud-playable") .on("click", "a.sound-cloud-playable", playSoundCloudFile)
|
||||
}
|
||||
|
||||
function playSoundCloudFile(e) {
|
||||
e.preventDefault();
|
||||
var url = $(this).attr("soundcloud_url")
|
||||
var cap = $(this).text()
|
||||
player.initialize(url, cap);
|
||||
app.layout.showDialog('sound-cloud-player-dialog');
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleFriendChange(evt) {
|
||||
if (isFriend()) {
|
||||
removeFriend(evt);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sendFriendRequest(evt);
|
||||
}
|
||||
return false;
|
||||
|
|
@ -176,8 +274,7 @@
|
|||
function handleFollowingChange(evt) {
|
||||
if (isFollowing()) {
|
||||
removeFollowing(false, userId);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
addFollowing();
|
||||
}
|
||||
return false;
|
||||
|
|
@ -221,10 +318,9 @@
|
|||
|
||||
function configureFriendButton() {
|
||||
if (isFriend()) {
|
||||
$('#btn-add-friend').text('DISCONNECT');
|
||||
}
|
||||
else {
|
||||
$('#btn-add-friend').text('CONNECT');
|
||||
$btnAddFriend.text('DISCONNECT');
|
||||
} else {
|
||||
$btnAddFriend.text('CONNECT');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -267,32 +363,31 @@
|
|||
function configureFollowingButton() {
|
||||
|
||||
if (isFollowing()) {
|
||||
$('#btn-follow-user').text('UNFOLLOW');
|
||||
}
|
||||
else {
|
||||
$('#btn-follow-user').text('FOLLOW');
|
||||
$btnFollowUser.text('UNFOLLOW');
|
||||
} else {
|
||||
$btnFollowUser.text('FOLLOW');
|
||||
}
|
||||
}
|
||||
|
||||
function configureEditProfileButton() {
|
||||
$('#btn-follow-user').click(addFollowing);
|
||||
$btnFollowUser.click(addFollowing);
|
||||
}
|
||||
|
||||
// refreshes the currently active tab
|
||||
function renderActive() {
|
||||
if ($('#profile-about-link').hasClass('active')) {
|
||||
if ($aboutLink.hasClass('active')) {
|
||||
renderAbout();
|
||||
}
|
||||
else if ($('#profile-history-link').hasClass('active')) {
|
||||
else if ($historyLink.hasClass('active')) {
|
||||
renderHistory();
|
||||
}
|
||||
else if ($('#profile-bands-link').hasClass('active')) {
|
||||
else if ($bandsLink.hasClass('active')) {
|
||||
renderBands();
|
||||
}
|
||||
else if ($('#profile-social-link').hasClass('active')) {
|
||||
else if ($socialLink.hasClass('active')) {
|
||||
renderSocial();
|
||||
}
|
||||
else if ($('#profile-favorites-link').hasClass('active')) {
|
||||
else if ($favoritesLink.hasClass('active')) {
|
||||
renderFavorites();
|
||||
}
|
||||
}
|
||||
|
|
@ -308,187 +403,203 @@
|
|||
})
|
||||
}
|
||||
|
||||
/****************** ABOUT TAB *****************/
|
||||
function renderAbout() {
|
||||
$('#profile-instruments').empty();
|
||||
|
||||
$('#profile-about').show();
|
||||
$('#profile-history').hide();
|
||||
$('#profile-bands').hide();
|
||||
$('#profile-social').hide();
|
||||
$('#profile-favorites').hide();
|
||||
|
||||
$('.profile-nav a.active').removeClass('active');
|
||||
$('.profile-nav a#profile-about-link').addClass('active');
|
||||
|
||||
bindAbout();
|
||||
function hideElements(elements) {
|
||||
$.each(elements, function(index, val) {
|
||||
val.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function bindAbout() {
|
||||
/****************** ABOUT TAB *****************/
|
||||
function renderAbout() {
|
||||
$instruments.empty();
|
||||
|
||||
$('#profile-instruments').empty();
|
||||
$aboutContent.show();
|
||||
$historyContent.hide();
|
||||
$bandsContent.hide();
|
||||
$socialContent.hide();
|
||||
$favoritesContent.hide();
|
||||
|
||||
$('.profile-nav a.active').removeClass('active');
|
||||
$aboutLink.addClass('active');
|
||||
}
|
||||
|
||||
function renderAllStats() {
|
||||
|
||||
if (!isCurrentUser()) {
|
||||
$btnEditBio.hide();
|
||||
$btnAddRecordings.hide();
|
||||
$btnAddSites.hide();
|
||||
$btnAddInterests.hide();
|
||||
}
|
||||
|
||||
if (user && $userName) {
|
||||
renderNameLocationStats();
|
||||
renderBio();
|
||||
renderMusicalExperience();
|
||||
renderPerformanceSamples();
|
||||
renderOnlinePresence();
|
||||
renderInterests();
|
||||
}
|
||||
}
|
||||
|
||||
function renderNameLocationStats() {
|
||||
// name
|
||||
$('#profile-username').html(user.name);
|
||||
$userName.html(user.name);
|
||||
|
||||
// avatar
|
||||
$('#profile-avatar').attr('src', context.JK.resolveAvatarUrl(user.photo_url));
|
||||
|
||||
// instruments
|
||||
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]
|
||||
});
|
||||
|
||||
$('#profile-instruments').append(instrumentHtml);
|
||||
}
|
||||
}
|
||||
$('#profile-genres').empty();
|
||||
for (var i=0; i< user.genres.length; i++) {
|
||||
$('#profile-genres').append(user.genres[i].description + '<br />');
|
||||
}
|
||||
$avatar.attr('src', context.JK.resolveAvatarUrl(user.photo_url));
|
||||
|
||||
// location
|
||||
$('#profile-location').html(user.location);
|
||||
$location.html(user.location);
|
||||
|
||||
$age.html(user.age ? user.age + " years old" : "");
|
||||
|
||||
// stats
|
||||
var text = user.friend_count > 1 || user.friend_count === 0 ? " Friends" : " Friend";
|
||||
$('#profile-friend-stats').html('<span class="friend-count">' + user.friend_count + '</span>' + text);
|
||||
$friendStats.html('<span class="friend-count">' + user.friend_count + '</span>' + text);
|
||||
|
||||
text = user.follower_count > 1 || user.follower_count === 0 ? " Followers" : " Follower";
|
||||
$('#profile-follower-stats').html('<span class="follower-count">' + user.follower_count + '</span>' + text);
|
||||
$followerStats.html('<span class="follower-count">' + user.follower_count + '</span>' + text);
|
||||
|
||||
if (isMusician()) {
|
||||
text = user.session_count > 1 || user.session_count === 0 ? " Sessions" : " Session";
|
||||
$('#profile-session-stats').html(user.session_count + text);
|
||||
$sessionStats.html(user.session_count + text);
|
||||
|
||||
text = user.recording_count > 1 || user.recording_count === 0 ? " Recordings" : " Recording";
|
||||
$('#profile-recording-stats').html(user.recording_count + text);
|
||||
$recordingStats.html(user.recording_count + text);
|
||||
} else {
|
||||
text = " Following";
|
||||
$('#profile-following-stats').html(user.following_count + text);
|
||||
$followingStats.html(user.following_count + text);
|
||||
text = user.favorite_count > 1 || user.favorite_count === 0 ? " Favorites" : " Favorite";
|
||||
$('#profile-favorite-stats').html(user.favorite_count + text);
|
||||
$favoriteStats.html(user.favorite_count + text);
|
||||
}
|
||||
|
||||
renderBio();
|
||||
}
|
||||
|
||||
/** The biography show/edit functionality */
|
||||
function renderBio() {
|
||||
$biography.html(user.biography ? user.biography : NOT_SPECIFIED_TEXT);
|
||||
if (isCurrentUser() && !user.biography) {
|
||||
$btnEditBio.show();
|
||||
} else {
|
||||
$btnEditBio.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function renderMusicalExperience() {
|
||||
profileUtils.renderMusicalExperience(user, $screen)
|
||||
}
|
||||
|
||||
function initializeBioVisibility() {
|
||||
function renderPerformanceSamples() {
|
||||
profileUtils.renderPerformanceSamples(user, $screen)
|
||||
}
|
||||
|
||||
$showBio.hide();
|
||||
$noBio.hide();
|
||||
$biographyEditor.hide();
|
||||
function renderOnlinePresence() {
|
||||
profileUtils.renderOnlinePresence(user, $screen)
|
||||
}
|
||||
|
||||
$bioTextArea.val(user.biography);
|
||||
function renderInterests() {
|
||||
// current interests
|
||||
var noInterests = !user.paid_sessions && !user.free_sessions && !user.cowriting && !user.virtual_band && !user.traditional_band;
|
||||
if (noInterests) {
|
||||
$noInterests.show();
|
||||
$paidGigSection.hide();
|
||||
$freeGigSection.hide();
|
||||
$cowritingSection.hide();
|
||||
$traditionalBandSection.hide();
|
||||
$virtualBandSection.hide();
|
||||
|
||||
if(user.biography) {
|
||||
|
||||
$showBio.show();
|
||||
if(isCurrentUser()) {
|
||||
$editBiographyButton.show();
|
||||
}
|
||||
else {
|
||||
$editBiographyButton.hide();
|
||||
}
|
||||
$biographyText.text(user.biography).show();
|
||||
if (isCurrentUser()) {
|
||||
$btnAddInterests.show();
|
||||
}
|
||||
else {
|
||||
if(isCurrentUser()) {
|
||||
$noBio.show();
|
||||
}
|
||||
} else {
|
||||
$btnAddInterests.hide();
|
||||
$noInterests.hide();
|
||||
|
||||
// paid sessions
|
||||
if (user.paid_sessions) {
|
||||
$paidGigSection.show();
|
||||
|
||||
var genreList = profileUtils.paidSessionGenreList(user.genres);
|
||||
$paidGigDetails.find("ul").html("");
|
||||
$paidGigDetails.find("ul").append('<li>Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
|
||||
var hourlyRate = user.paid_sessions_hourly_rate;
|
||||
$paidGigDetails.find("ul").append('<li>Hourly rate = ' + (hourlyRate ? hourlyRate : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
|
||||
var dailyRate = user.paid_sessions_daily_rate;
|
||||
$paidGigDetails.find("ul").append('<li>Day rate = ' + (dailyRate ? dailyRate : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
} else {
|
||||
$paidGigSection.hide();
|
||||
}
|
||||
|
||||
// free sessions
|
||||
if (user.free_sessions) {
|
||||
$freeGigSection.show();
|
||||
$freeGigDetails.find("ul").html("");
|
||||
var genreList = profileUtils.freeSessionGenreList(user.genres);
|
||||
$freeGigDetails.find("ul").append('<li>Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
} else {
|
||||
$freeGigSection.hide();
|
||||
}
|
||||
|
||||
// cowriting
|
||||
if (user.cowriting) {
|
||||
$cowritingSection.show();
|
||||
$cowritingDetails.find("ul").html("");
|
||||
var genreList = profileUtils.cowritingGenreList(user.genres);
|
||||
$cowritingDetails.find("ul").append('<li>Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
|
||||
var purpose = user.cowriting_purpose;
|
||||
$cowritingDetails.find("ul").append('<li>Purpose: ' + (purpose ? profileUtils.cowritingPurposeMap[purpose] : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
} else {
|
||||
$cowritingSection.hide();
|
||||
}
|
||||
|
||||
// traditional bands
|
||||
if (user.traditional_band) {
|
||||
$traditionalBandSection.show();
|
||||
$traditionalBandDetails.find("ul").html("");
|
||||
var genreList = profileUtils.traditionalBandGenreList(user.genres);
|
||||
$traditionalBandDetails.find("ul").append('<li>Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
|
||||
var commitment = user.traditional_band_commitment;
|
||||
$traditionalBandDetails.find("ul").append('<li>Commitment: ' + (commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
|
||||
var canTour = user.traditional_band_touring;
|
||||
var canTourResponse = canTour ? "Yes" : (canTour === false ? "No" : NOT_SPECIFIED_TEXT);
|
||||
$traditionalBandDetails.find("ul").append('<li>Touring: ' + canTourResponse + '</li>');
|
||||
} else {
|
||||
$traditionalBandSection.hide();
|
||||
}
|
||||
|
||||
// virtual band
|
||||
if (user.virtual_band) {
|
||||
$virtualBandSection.show();
|
||||
$virtualBandDetails.find("ul").html("");
|
||||
var genreList = profileUtils.virtualBandGenreList(user.genres);
|
||||
$virtualBandDetails.find("ul").append('<li>Genre(s): ' + (genreList.length > 0 ? genreList : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
|
||||
var commitment = user.virtual_band_commitment;
|
||||
$virtualBandDetails.find("ul").append('<li>Commitment: ' + (commitment ? profileUtils.bandCommitmentMap[commitment] : NOT_SPECIFIED_TEXT) + '</li>');
|
||||
} else {
|
||||
$virtualBandSection.hide();
|
||||
}
|
||||
}
|
||||
|
||||
var $bioTextArea = $('.user-biography', profileScreen);
|
||||
var $showBio = $('.have-bio', profileScreen);
|
||||
var $noBio = $('.no-bio', profileScreen);
|
||||
var $biographyEditor = $('.update-biography', profileScreen);
|
||||
var $addBiographyButton = $('a.enter-bio', profileScreen);
|
||||
var $editBiographyButton = $('#profile-edit-biography', profileScreen);
|
||||
var $submitBiographyButton = $('#btn-update-user-biography', profileScreen);
|
||||
var $cancelBiographyButton = $('#btn-cancel-user-biography', profileScreen);
|
||||
var $biographyText = $('#profile-biography', profileScreen);
|
||||
|
||||
initializeBioVisibility();
|
||||
|
||||
$addBiographyButton.unbind('click').click(function() {
|
||||
$biographyEditor.val(user.biography).show();
|
||||
return false;
|
||||
});
|
||||
|
||||
$editBiographyButton.unbind('click').click(function() {
|
||||
$editBiographyButton.hide();
|
||||
$biographyText.hide();
|
||||
$bioTextArea.val(user.biography);
|
||||
$biographyEditor.show();
|
||||
return false;
|
||||
})
|
||||
|
||||
$submitBiographyButton.unbind('click').click(function() {
|
||||
var bio = $bioTextArea.val();
|
||||
$bioTextArea.closest('div.field').removeClass('error');
|
||||
$('.error-text', $bioTextArea.closest('div.field')).remove();
|
||||
userDefer = rest.updateUser({
|
||||
biography: bio
|
||||
})
|
||||
.done(function(response) {
|
||||
user = response;
|
||||
initializeBioVisibility();
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
var errors = JSON.parse(jqXHR.responseText)
|
||||
var biography = context.JK.format_errors("biography", errors);
|
||||
if(biography != null) {
|
||||
$bioTextArea.closest('div.field').addClass('error').end().after(biography);
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(jqXHR, "Unable to update biography")
|
||||
}
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(jqXHR, "Unable to update biography")
|
||||
}
|
||||
})
|
||||
return false;
|
||||
})
|
||||
|
||||
$cancelBiographyButton.unbind('click').click(function() {
|
||||
initializeBioVisibility();
|
||||
return false;
|
||||
})
|
||||
}
|
||||
|
||||
/****************** SOCIAL TAB *****************/
|
||||
function renderSocial() {
|
||||
$('#profile-social-friends').empty();
|
||||
$('#profile-social-followings').empty();
|
||||
$('#profile-social-followers').empty();
|
||||
$socialFriends.empty();
|
||||
$socialFollowings.empty();
|
||||
$socialFollowers.empty();
|
||||
|
||||
$('#profile-about').hide();
|
||||
$('#profile-history').hide();
|
||||
$('#profile-bands').hide();
|
||||
$('#profile-social').show();
|
||||
$('#profile-favorites').hide();
|
||||
$aboutContent.hide();
|
||||
$historyContent.hide();
|
||||
$bandsContent.hide();
|
||||
$socialContent.show();
|
||||
$favoritesContent.hide();
|
||||
|
||||
$('.profile-nav a.active').removeClass('active');
|
||||
$('.profile-nav a#profile-social-link').addClass('active');
|
||||
$socialLink.addClass('active');
|
||||
|
||||
bindSocial();
|
||||
}
|
||||
|
|
@ -511,11 +622,11 @@
|
|||
type: "Friends"
|
||||
});
|
||||
|
||||
$('#profile-social-friends').append(friendHtml);
|
||||
$socialFriends.append(friendHtml);
|
||||
});
|
||||
}
|
||||
else {
|
||||
$('#profile-social-friends').html(' ');
|
||||
$socialFriends.html(' ');
|
||||
}
|
||||
context.JK.bindHoverEvents();
|
||||
})
|
||||
|
|
@ -536,11 +647,11 @@
|
|||
location: val.location
|
||||
});
|
||||
|
||||
$('#profile-social-followings').append(followingHtml);
|
||||
$socialFollowings.append(followingHtml);
|
||||
});
|
||||
}
|
||||
else {
|
||||
$('#profile-social-followings').html(' ');
|
||||
$socialFollowings.html(' ');
|
||||
}
|
||||
context.JK.bindHoverEvents();
|
||||
})
|
||||
|
|
@ -559,7 +670,7 @@
|
|||
location: val.location
|
||||
});
|
||||
|
||||
$('#profile-social-followers').append(followerHtml);
|
||||
$socialFollowers.append(followerHtml);
|
||||
});
|
||||
context.JK.bindHoverEvents();
|
||||
})
|
||||
|
|
@ -568,14 +679,14 @@
|
|||
|
||||
/****************** HISTORY TAB *****************/
|
||||
function renderHistory() {
|
||||
$('#profile-about').hide();
|
||||
$('#profile-history').show();
|
||||
$('#profile-bands').hide();
|
||||
$('#profile-social').hide();
|
||||
$('#profile-favorites').hide();
|
||||
$aboutContent.hide();
|
||||
$historyContent.show();
|
||||
$bandsContent.hide();
|
||||
$socialContent.hide();
|
||||
$favoritesContent.hide();
|
||||
|
||||
$('.profile-nav a.active').removeClass('active');
|
||||
$('.profile-nav a#profile-history-link').addClass('active');
|
||||
$historyLink.addClass('active');
|
||||
|
||||
bindHistory();
|
||||
}
|
||||
|
|
@ -586,16 +697,16 @@
|
|||
|
||||
/****************** BANDS TAB *****************/
|
||||
function renderBands() {
|
||||
$('#profile-bands').empty();
|
||||
$bandsContent.empty();
|
||||
|
||||
$('#profile-about').hide();
|
||||
$('#profile-history').hide();
|
||||
$('#profile-bands').show();
|
||||
$('#profile-social').hide();
|
||||
$('#profile-favorites').hide();
|
||||
$aboutContent.hide();
|
||||
$historyContent.hide();
|
||||
$bandsContent.show();
|
||||
$socialContent.hide();
|
||||
$favoritesContent.hide();
|
||||
|
||||
$('.profile-nav a.active').removeClass('active');
|
||||
$('.profile-nav a#profile-bands-link').addClass('active');
|
||||
$bandsLink.addClass('active');
|
||||
|
||||
bindBands();
|
||||
}
|
||||
|
|
@ -606,7 +717,7 @@
|
|||
.done(function (response) {
|
||||
if ((!response || response.length === 0) && isCurrentUser()) {
|
||||
var noBandHtml = $('#template-no-bands').html();
|
||||
$("#profile-bands").html(noBandHtml);
|
||||
$bandsContent.html(noBandHtml);
|
||||
}
|
||||
else {
|
||||
addMoreBandsLink();
|
||||
|
|
@ -652,8 +763,8 @@
|
|||
bandId: val.id,
|
||||
biography: val.biography,
|
||||
profile_url: "/client#/bandProfile/" + val.id,
|
||||
band_edit_url: "/client#/band/setup/" + val.id + '/step1',
|
||||
band_member_url: "/client#/band/setup/" + val.id + '/step2',
|
||||
band_edit_url: "/client#/band/setup/" + val.id + '/step0',
|
||||
band_member_url: "/client#/band/setup/" + val.id + '/step4',
|
||||
avatar_url: context.JK.resolveBandAvatarUrl(val.photo_url),
|
||||
name: val.name,
|
||||
location: val.location,
|
||||
|
|
@ -664,12 +775,12 @@
|
|||
musicians: musicianHtml
|
||||
});
|
||||
|
||||
$('#profile-bands').append(bandHtml);
|
||||
|
||||
$('.profile-band-link-member-true').each(function(idx) {
|
||||
$bandsContent.append(bandHtml);
|
||||
|
||||
$('.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();
|
||||
});
|
||||
|
||||
|
|
@ -689,7 +800,7 @@
|
|||
function addMoreBandsLink() {
|
||||
if (isCurrentUser()) {
|
||||
var moreBandsHtml = $('#template-more-bands').html();
|
||||
$("#profile-bands").append(moreBandsHtml);
|
||||
$bandsContent.append(moreBandsHtml);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -716,13 +827,13 @@
|
|||
}
|
||||
|
||||
function updateFollowingCount(value) {
|
||||
var followingCount = $('#profile-follower-stats span.follower-count');
|
||||
followingCount.text(value + parseInt(followingCount.text()));
|
||||
var $followingCount = $('#follower-stats span.follower-count');
|
||||
$followingCount.text(value + parseInt($followingCount.text()));
|
||||
}
|
||||
|
||||
function updateBandFollowingCount(bandId, value) {
|
||||
var bandFollowing = $('div[band-id="' + bandId + '"].profile-bands span.follower-count');
|
||||
bandFollowing.text(value + parseInt(bandFollowing.text()));
|
||||
var $bandFollowing = $('div[band-id="' + bandId + '"].profile-bands span.follower-count');
|
||||
$bandFollowing.text(value + parseInt($bandFollowing.text()));
|
||||
}
|
||||
|
||||
function addBandFollowing(evt) {
|
||||
|
|
@ -734,7 +845,6 @@
|
|||
|
||||
rest.addFollowing(newFollowing)
|
||||
.done(function (response) {
|
||||
logger.debug("following band " + bandId);
|
||||
updateBandFollowingCount(bandId, 1); // increase counter
|
||||
configureBandFollowingButton(true, bandId);
|
||||
context.JK.GA.trackJKSocial(context.JK.GA.Categories.jkFollow, context.JK.GA.JKSocialTargets.band);
|
||||
|
|
@ -743,7 +853,7 @@
|
|||
}
|
||||
|
||||
function configureBandFollowingButton(following, bandId) {
|
||||
var $btnFollowBand = $('div[band-id=' + bandId + ']', '#profile-bands').find('#btn-follow-band-2');
|
||||
var $btnFollowBand = $('div[band-id=' + bandId + ']', '#bands-content').find('#btn-follow-band');
|
||||
$btnFollowBand.unbind("click");
|
||||
|
||||
if (following) {
|
||||
|
|
@ -753,8 +863,7 @@
|
|||
evt.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$btnFollowBand.text('FOLLOW');
|
||||
$btnFollowBand.click(addBandFollowing);
|
||||
}
|
||||
|
|
@ -762,14 +871,14 @@
|
|||
|
||||
/****************** FAVORITES TAB *****************/
|
||||
function renderFavorites() {
|
||||
$('#profile-about').hide();
|
||||
$('#profile-history').hide();
|
||||
$('#profile-bands').hide();
|
||||
$('#profile-social').hide();
|
||||
$('#profile-favorites').show();
|
||||
$aboutContent.hide();
|
||||
$historyContent.hide();
|
||||
$bandsContent.hide();
|
||||
$socialContent.hide();
|
||||
$favoritesContent.show();
|
||||
|
||||
$('.profile-nav a.active').removeClass('active');
|
||||
$('.profile-nav a#profile-favorites-link').addClass('active');
|
||||
$favoritesLink.addClass('active');
|
||||
|
||||
bindFavorites();
|
||||
}
|
||||
|
|
@ -780,16 +889,16 @@
|
|||
|
||||
function initializeFeed() {
|
||||
|
||||
var $scroller = profileScreen.find('.content-body-scroller#user-profile-feed-scroller');
|
||||
var $content = profileScreen.find('.feed-content#user-profile-feed-entry-list');
|
||||
var $noMoreFeeds = $('#user-profile-end-of-feeds-list');
|
||||
var $refresh = profileScreen.find('.btn-refresh-entries');
|
||||
var $sortFeedBy = profileScreen.find('#feed_order_by');
|
||||
var $includeDate = profileScreen.find('#feed_date');
|
||||
var $includeType = profileScreen.find('#feed_show');
|
||||
var $scroller = $screen.find('.content-body-scroller#user-profile-feed-scroller');
|
||||
var $content = $screen.find('.feed-content#user-profile-feed-entry-list');
|
||||
var $noMoreFeeds = $screen.find('#user-profile-end-of-feeds-list');
|
||||
var $refresh = $screen.find('.btn-refresh-entries');
|
||||
var $sortFeedBy = $screen.find('#feed_order_by');
|
||||
var $includeDate = $screen.find('#feed_date');
|
||||
var $includeType = $screen.find('#feed_show');
|
||||
|
||||
feed = new context.JK.Feed(app);
|
||||
feed.initialize(profileScreen, $scroller, $content, $noMoreFeeds, $refresh, $sortFeedBy, $includeDate, $includeType, {time_range: 'all'});
|
||||
feed.initialize($screen, $scroller, $content, $noMoreFeeds, $refresh, $sortFeedBy, $includeDate, $includeType, {time_range: 'all'});
|
||||
}
|
||||
|
||||
function initialize(textMessageDialogInstance) {
|
||||
|
|
@ -800,9 +909,9 @@
|
|||
'beforeHide' : beforeHide
|
||||
};
|
||||
app.bindScreen('profile', screenBindings);
|
||||
profileScreen = $('#user-profile');
|
||||
events();
|
||||
initializeFeed();
|
||||
player = new context.JK.SoundCloudPlayerDialog(app);
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,515 @@
|
|||
/**
|
||||
* Common utility functions.
|
||||
*/
|
||||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
var profileUtils = {};
|
||||
context.JK.ProfileUtils = profileUtils;
|
||||
|
||||
// genre types
|
||||
var PROFILE_GENRE_TYPE = 'profile';
|
||||
var VIRTUAL_BAND_GENRE_TYPE = 'virtual_band';
|
||||
var TRADITIONAL_BAND_GENRE_TYPE = 'traditional_band';
|
||||
var PAID_SESSION_GENRE_TYPE = 'paid_sessions';
|
||||
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"},
|
||||
SOUNDCLOUD: {description: "soundcloud"},
|
||||
YOUTUBE: {description: "youtube"}
|
||||
};
|
||||
|
||||
// online presence types
|
||||
profileUtils.ONLINE_PRESENCE_TYPES = {
|
||||
SOUNDCLOUD: {description: "soundcloud"},
|
||||
REVERBNATION: {description: "reverbnation"},
|
||||
BANDCAMP: {description: "bandcamp"},
|
||||
FANDALISM: {description: "fandalism"},
|
||||
YOUTUBE: {description: "youtube"},
|
||||
FACEBOOK: {description: "facebook"},
|
||||
TWITTER: {description: "twitter"}
|
||||
};
|
||||
|
||||
var USER_TYPE = 'JamRuby::User';
|
||||
|
||||
profileUtils.skillLevelMap = {
|
||||
"1": "Amateur",
|
||||
"2": "Professional"
|
||||
};
|
||||
|
||||
profileUtils.gigMap = {
|
||||
"": "not specified",
|
||||
"0": "zero",
|
||||
"1": "under 10",
|
||||
"2": "10 to 50",
|
||||
"3": "50 to 100",
|
||||
"4": "over 100"
|
||||
};
|
||||
|
||||
profileUtils.studioMap = {
|
||||
"0": "zero",
|
||||
"1": "under 10",
|
||||
"2": "10 to 50",
|
||||
"3": "50 to 100",
|
||||
"4": "over 100"
|
||||
};
|
||||
|
||||
profileUtils.cowritingPurposeMap = {
|
||||
"1": "just for fun",
|
||||
"2": "sell music"
|
||||
};
|
||||
|
||||
profileUtils.bandCommitmentMap = {
|
||||
"1": "infrequent",
|
||||
"2": "once a week",
|
||||
"3": "2-3 times a week",
|
||||
"4": "4+ times a week"
|
||||
}
|
||||
|
||||
function buildGenreList(genres) {
|
||||
var list = '';
|
||||
|
||||
for (var i=0; i < genres.length; i++) {
|
||||
list = list.concat(genres[i].genre_id);
|
||||
if (i !== genres.length - 1) {
|
||||
list = list.concat(', ');
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// 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"), {}, {})
|
||||
})
|
||||
}
|
||||
|
||||
// profile genres
|
||||
profileUtils.profileGenres = function(genres) {
|
||||
var matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === PROFILE_GENRE_TYPE;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.profileGenreList = function(genres) {
|
||||
var matches = profileUtils.profileGenres(genres);
|
||||
return buildGenreList(matches);
|
||||
}
|
||||
|
||||
// virtual band genres
|
||||
profileUtils.virtualBandGenres = function(genres) {
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === VIRTUAL_BAND_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.virtualBandGenreList = function(genres) {
|
||||
var matches = profileUtils.virtualBandGenres(genres);
|
||||
return buildGenreList(matches);
|
||||
}
|
||||
|
||||
// traditional band genres
|
||||
profileUtils.traditionalBandGenres = function(genres) {
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === TRADITIONAL_BAND_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.traditionalBandGenreList = function(genres) {
|
||||
var matches = profileUtils.traditionalBandGenres(genres);
|
||||
return buildGenreList(matches);
|
||||
}
|
||||
|
||||
// paid session genres
|
||||
profileUtils.paidSessionGenres = function(genres) {
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === PAID_SESSION_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.paidSessionGenreList = function(genres) {
|
||||
var matches = profileUtils.paidSessionGenres(genres);
|
||||
return buildGenreList(matches);
|
||||
}
|
||||
|
||||
// free session genres
|
||||
profileUtils.freeSessionGenres = function(genres) {
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === FREE_SESSION_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.freeSessionGenreList = function(genres) {
|
||||
var matches = profileUtils.freeSessionGenres(genres);
|
||||
return buildGenreList(matches);
|
||||
}
|
||||
|
||||
// cowriting genres
|
||||
profileUtils.cowritingGenres = function(genres) {
|
||||
var matches = [];
|
||||
if (genres) {
|
||||
matches = $.grep(genres, function(g) {
|
||||
return g.player_type === USER_TYPE && g.genre_type === COWRITING_GENRE_TYPE;
|
||||
});
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.cowritingGenreList = function(genres) {
|
||||
var matches = profileUtils.cowritingGenres(genres);
|
||||
return buildGenreList(matches);
|
||||
}
|
||||
|
||||
profileUtils.jamkazamSamples = function(samples) {
|
||||
var matches = $.grep(samples, function(s) {
|
||||
return s.service_type === profileUtils.SAMPLE_TYPES.JAMKAZAM.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.soundCloudSamples = function(samples) {
|
||||
var matches = $.grep(samples, function(s) {
|
||||
return s.service_type === profileUtils.SAMPLE_TYPES.SOUNDCLOUD.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.youTubeSamples = function(samples) {
|
||||
var matches = $.grep(samples, function(s) {
|
||||
return s.service_type === profileUtils.SAMPLE_TYPES.YOUTUBE.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.soundCloudPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.SOUNDCLOUD.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.reverbNationPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.REVERBNATION.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.bandCampPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.BANDCAMP.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.fandalismPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.FANDALISM.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.youTubePresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.YOUTUBE.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.facebookPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.FACEBOOK.description;
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
profileUtils.twitterPresences = function(presences) {
|
||||
var matches = $.grep(presences, function(p) {
|
||||
return p.service_type === profileUtils.ONLINE_PRESENCE_TYPES.TWITTER.description;
|
||||
});
|
||||
|
||||
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("<a class='jamkazam-playable' href='/recordings/" + sample.claimed_recording.id + "' rel='external'>" + formatTitle(sample.claimed_recording.name) + "</a><br/>");
|
||||
});
|
||||
|
||||
$.each(soundCloudSamples, function(index, sample) {
|
||||
$soundCloudSamples.append("<a class='sound-cloud-playable' href='' soundcloud_url='" + sample.url + "'>" + formatTitle(sample.description) + "</a><br/>");
|
||||
});
|
||||
|
||||
$.each(youTubeSamples, function(index, sample) {
|
||||
$youTubeSamples.append("<a class='youtube-playable' href='" + sample.url + "' rel='external'>" + formatTitle(sample.description) + "</a><br/>");
|
||||
});
|
||||
}
|
||||
}// 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);
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ context.JK ||= {};
|
|||
|
||||
context.JK.SiteValidator = class SiteValidator
|
||||
|
||||
constructor: (site_type) ->
|
||||
constructor: (site_type, success_callback, fail_callback, parent) ->
|
||||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@site_type = site_type
|
||||
@input_div = $(".site_validator#"+site_type+"_validator")
|
||||
@input_div = $(".site_validator."+site_type+"_validator", parent)
|
||||
@data_input = @input_div.find('input')
|
||||
|
||||
@logger = context.JK.logger
|
||||
@spinner = @input_div.find('span.spinner-small')
|
||||
@checkmark = @input_div.find('.validate-checkmark')
|
||||
|
|
@ -18,6 +19,8 @@ context.JK.SiteValidator = class SiteValidator
|
|||
@is_rec_src = false
|
||||
@deferred_status_check = null
|
||||
@is_validating = false
|
||||
@success_callback = success_callback
|
||||
@fail_callback = fail_callback
|
||||
|
||||
init: () =>
|
||||
this.renderErrors({})
|
||||
|
|
@ -32,7 +35,7 @@ context.JK.SiteValidator = class SiteValidator
|
|||
|
||||
dataToValidate: () =>
|
||||
url = @data_input.val()
|
||||
if 0 < url.length
|
||||
if url && 0 < url.length
|
||||
url.substring(0,2000)
|
||||
else
|
||||
null
|
||||
|
|
@ -47,12 +50,14 @@ context.JK.SiteValidator = class SiteValidator
|
|||
@checkmark.hide()
|
||||
yn
|
||||
|
||||
didBlur: () =>
|
||||
didBlur: () =>
|
||||
if this.showFormatStatus()
|
||||
this.validateSite()
|
||||
|
||||
validateSite: () =>
|
||||
unless data = this.dataToValidate()
|
||||
if @success_callback
|
||||
@success_callback(@input_div)
|
||||
return null
|
||||
this.setSiteStatus(null)
|
||||
@spinner.show()
|
||||
|
|
@ -68,13 +73,18 @@ context.JK.SiteValidator = class SiteValidator
|
|||
this.renderErrors({})
|
||||
if @deferred_status_check
|
||||
@deferred_status_check.resolve()
|
||||
if @success_callback
|
||||
@success_callback(@input_div)
|
||||
else
|
||||
this.setSiteStatus(false)
|
||||
this.renderErrors(response)
|
||||
if @deferred_status_check
|
||||
@deferred_status_check.reject()
|
||||
if @fail_callback
|
||||
@fail_callback(@input_div)
|
||||
|
||||
@deferred_status_check = null
|
||||
@logger.debug("site_status = "+@site_status)
|
||||
@logger.debug("site_status = " + @site_status)
|
||||
|
||||
processSiteCheckFail: (response) =>
|
||||
@logger.error("site check error")
|
||||
|
|
@ -90,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()
|
||||
|
|
@ -110,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()
|
||||
|
|
@ -118,31 +128,42 @@ context.JK.SiteValidator = class SiteValidator
|
|||
dfr.reject()
|
||||
return dfr.promise()
|
||||
|
||||
|
||||
context.JK.RecordingSourceValidator = class RecordingSourceValidator extends SiteValidator
|
||||
constructor: (site_type) ->
|
||||
super(site_type)
|
||||
|
||||
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
|
||||
@add_btn = @input_div.find('a.add-recording-source')
|
||||
@site_success_callback = success_callback
|
||||
@site_fail_callback = fail_callback
|
||||
|
||||
init: (sources) =>
|
||||
super()
|
||||
if sources
|
||||
@recording_sources = sources
|
||||
@add_btn.on 'click', =>
|
||||
@add_btn.off('click').on 'click', =>
|
||||
this.attemptAdd()
|
||||
|
||||
processSiteCheckSucceed: (response) =>
|
||||
super(response)
|
||||
@add_btn.removeClass('disabled')
|
||||
@recording_sources.push({ url: response.data, recording_id: response.recording_id })
|
||||
|
||||
if @site_status
|
||||
@recording_sources.push({ url: response.data, recording_id: response.recording_id, recording_title: response.recording_title })
|
||||
if @site_success_callback
|
||||
@site_success_callback(@input_div)
|
||||
else
|
||||
if @site_fail_callback
|
||||
@site_fail_callback(@input_div)
|
||||
|
||||
processSiteCheckFail: (response) =>
|
||||
super(response)
|
||||
@add_btn.removeClass('disabled')
|
||||
if @site_fail_callback
|
||||
@site_fail_callback(@input_div)
|
||||
|
||||
didBlur: () =>
|
||||
didBlur: () =>
|
||||
# do nothing, validate on add only
|
||||
|
||||
validateSite: () =>
|
||||
|
|
@ -156,12 +177,16 @@ 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: () =>
|
||||
@recording_sources
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,24 @@
|
|||
});
|
||||
}
|
||||
|
||||
function launchInstrumentSelectorDialog(type, instruments, callback) {
|
||||
var instrumentSelectorDialog = new JK.InstrumentSelectorDialog(JK.app, type, instruments, callback);
|
||||
instrumentSelectorDialog.initialize();
|
||||
return instrumentSelectorDialog.showDialog();
|
||||
}
|
||||
|
||||
function launchGenreSelectorDialog(type, genres, callback) {
|
||||
var genreSelectorDialog = new JK.GenreSelectorDialog(JK.app, type, genres, callback);
|
||||
genreSelectorDialog.initialize();
|
||||
return genreSelectorDialog.showDialog();
|
||||
}
|
||||
|
||||
function launchRecordingSelectorDialog(recordings, selectedRecordings, callback) {
|
||||
var recordingSelectorDialog = new JK.RecordingSelectorDialog(JK.app, recordings, selectedRecordings, callback);
|
||||
recordingSelectorDialog.initialize();
|
||||
return recordingSelectorDialog.showDialog();
|
||||
}
|
||||
|
||||
this.addSessionLike = addSessionLike;
|
||||
this.addRecordingLike = addRecordingLike;
|
||||
this.launchCommentDialog = launchCommentDialog;
|
||||
|
|
@ -70,6 +88,9 @@
|
|||
this.launchRsvpCancelDialog = launchRsvpCancelDialog;
|
||||
this.launchRsvpCreateSlotDialog = launchRsvpCreateSlotDialog;
|
||||
this.launchSessionStartDialog = launchSessionStartDialog;
|
||||
this.launchGenreSelectorDialog = launchGenreSelectorDialog;
|
||||
this.launchInstrumentSelectorDialog = launchInstrumentSelectorDialog;
|
||||
this.launchRecordingSelectorDialog = launchRecordingSelectorDialog;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
var logger = context.JK.logger;
|
||||
var AUDIO_DEVICE_BEHAVIOR = context.JK.AUDIO_DEVICE_BEHAVIOR;
|
||||
|
|
@ -23,6 +22,9 @@
|
|||
var os = null;
|
||||
|
||||
var reactHovers = []
|
||||
context.JK.getGenreList = function() {
|
||||
return context.JK.Rest().getGenres();
|
||||
}
|
||||
|
||||
context.JK.stringToBool = function (s) {
|
||||
switch (s.toLowerCase()) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
context.JK.ShowRecording = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = JK.Rest();
|
||||
var ui = context.JK.UIHelper();
|
||||
var ui = new context.JK.UIHelper(app);
|
||||
var recordingId = null;
|
||||
var claimedRecordingId = null;
|
||||
var $scope = $(".landing-details");
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
context.JK.ShowMusicSession = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = JK.Rest();
|
||||
var ui = context.JK.UIHelper();
|
||||
var ui = new context.JK.UIHelper(app);
|
||||
var sessionId = null;
|
||||
var $scope = $(".landing-details");
|
||||
var $controls = null;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
|
||||
form {
|
||||
padding-right:10%;
|
||||
//padding-right:10%;
|
||||
}
|
||||
|
||||
label {
|
||||
|
|
@ -107,6 +107,14 @@
|
|||
margin-right:17%;
|
||||
}
|
||||
|
||||
textarea.biography {
|
||||
width: 80%;
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-right: 125px;
|
||||
}
|
||||
|
||||
.location {
|
||||
position:relative;
|
||||
|
|
@ -134,25 +142,6 @@
|
|||
white-space: normal;
|
||||
}
|
||||
|
||||
.profile-instrumentlist {
|
||||
background-color: #C5C5C5;
|
||||
border: medium none;
|
||||
box-shadow: 2px 2px 3px 0 #888888 inset;
|
||||
color: #000;
|
||||
font-size: 14px;
|
||||
height: 100px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
|
||||
.easydropdown-wrapper {
|
||||
width:100%;
|
||||
}
|
||||
|
||||
select, .easydropdown {
|
||||
@include flat_dropdown;
|
||||
}
|
||||
}
|
||||
|
||||
.account-sub-description {
|
||||
display: block;
|
||||
white-space: normal;
|
||||
|
|
@ -212,11 +201,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
div.profile-instrumentlist table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 6px;
|
||||
}
|
||||
|
||||
.account-edit-email, .account-edit-password {
|
||||
width:35%;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
@import "common.css.scss";
|
||||
|
||||
|
||||
#account-profile-experience {
|
||||
.genres {
|
||||
width:100%;
|
||||
height:200px;
|
||||
background-color:#c5c5c5;
|
||||
border:none;
|
||||
-webkit-box-shadow: inset 2px 2px 3px 0px #888;
|
||||
box-shadow: inset 2px 2px 3px 0px #888;
|
||||
color:#000;
|
||||
overflow:auto;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.instruments {
|
||||
background-color: #C5C5C5;
|
||||
border: medium none;
|
||||
box-shadow: 2px 2px 3px 0 #888888 inset;
|
||||
color: #000;
|
||||
font-size: 14px;
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
width: 85%;
|
||||
|
||||
.easydropdown-wrapper {
|
||||
width:100%;
|
||||
}
|
||||
|
||||
select, .easydropdown {
|
||||
@include flat_dropdown;
|
||||
}
|
||||
}
|
||||
|
||||
div.instruments table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 6px;
|
||||
}
|
||||
|
||||
div.actions {
|
||||
margin-right: 100px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
@import "common.css.scss";
|
||||
|
||||
#account-profile-interests {
|
||||
.interest {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
a.help {
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
div.genres {
|
||||
width: 20%;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
a.select-genre {
|
||||
text-decoration: underline;
|
||||
font-size: 12px;
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
||||
span.genre-list {
|
||||
font-style: italic;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.interest-options {
|
||||
width: 30%;
|
||||
margin-bottom: 15px;
|
||||
|
||||
label {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
input[type=text].rate {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
@import "common.css.scss";
|
||||
@import "site_validator.css.scss";
|
||||
|
||||
.profile-online-sample-controls {
|
||||
table.profile-table {
|
||||
width: 100%;
|
||||
tr:nth-child(even) td {
|
||||
padding: 0.25em 0.25em 1em 0.25em;
|
||||
vertical-align: top;
|
||||
}
|
||||
tr:nth-child(odd) td {
|
||||
padding: 0.25em;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.sample {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.presence {
|
||||
margin: 3px 30px 15px 0px;
|
||||
}
|
||||
|
||||
.site_validator {
|
||||
a, .spinner-small {
|
||||
margin: 1px 1px 2px 2px;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,353 +1,466 @@
|
|||
@import "client/common.css.scss";
|
||||
|
||||
#band-setup, #band-profile {
|
||||
font-family: Raleway, Arial, Helvetica, verdana, arial, sans-serif;
|
||||
.band-field {
|
||||
input[type="text"], select, textarea {
|
||||
@include border_box_sizing;
|
||||
width: 100%;
|
||||
padding: 2px 4px 2px 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.band-setup-bio {
|
||||
height:90px;
|
||||
overflow:auto;
|
||||
}
|
||||
textarea {
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.band-setup-genres {
|
||||
width:100%;
|
||||
height:90px;
|
||||
background-color:#c5c5c5;
|
||||
border:none;
|
||||
-webkit-box-shadow: inset 2px 2px 3px 0px #888;
|
||||
box-shadow: inset 2px 2px 3px 0px #888;
|
||||
color:#000;
|
||||
overflow:auto;
|
||||
font-size:14px;
|
||||
}
|
||||
}
|
||||
|
||||
.band-setup-photo {
|
||||
|
||||
.avatar-space {
|
||||
color: $color2;
|
||||
margin: 20px;
|
||||
position:relative;
|
||||
min-height:300px;
|
||||
|
||||
img.preview_profile_avatar {
|
||||
table.summary-table {
|
||||
tr {
|
||||
td {
|
||||
padding-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.spinner-large {
|
||||
width:300px;
|
||||
height:300px;
|
||||
line-height: 300px;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index: 2000; // to win over jcrop
|
||||
}
|
||||
|
||||
.no-avatar-space {
|
||||
border:1px dotted $color2;
|
||||
|
||||
color: $color2;
|
||||
width:300px;
|
||||
height:300px;
|
||||
line-height: 300px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
background-color:$ColorTextBoxBackground;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.band-profile-header {
|
||||
padding:20px;
|
||||
height:120px;
|
||||
}
|
||||
// Mimic style of easydropdown selects:
|
||||
input[type="number"] {
|
||||
border-radius: 6px;
|
||||
background-color: #c5c5c5;
|
||||
border-right-style: outset;
|
||||
border-bottom-style: outset;
|
||||
height: 15px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.band-profile-header h2 {
|
||||
font-weight:200;
|
||||
font-size: 28px;
|
||||
float:left;
|
||||
margin: 0px 150px 0px 0px;
|
||||
}
|
||||
.content-body-scroller {
|
||||
|
||||
}
|
||||
|
||||
.band-profile-status {
|
||||
font-size:12px;
|
||||
float:left;
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
line-height:30px;
|
||||
}
|
||||
|
||||
.band-profile-photo {
|
||||
height: 95px;
|
||||
width: 15%;
|
||||
float:left;
|
||||
}
|
||||
|
||||
.band-profile-nav {
|
||||
width:85%;
|
||||
position:relative;
|
||||
float:right;
|
||||
margin-right:-10px;
|
||||
}
|
||||
|
||||
.band-profile-nav a {
|
||||
width:24%;
|
||||
text-align:center;
|
||||
height: 27px;
|
||||
display: block;
|
||||
float:left;
|
||||
margin-right:5px;
|
||||
vertical-align:bottom;
|
||||
padding-top:65px;
|
||||
background-color:#535353;
|
||||
color:#ccc;
|
||||
font-size:17px;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.band-profile-nav a:hover {
|
||||
background-color:#666;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.band-profile-nav a.active {
|
||||
background-color:#ed3618;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.band-profile-nav a.active:hover {
|
||||
background-color:#ed3618;
|
||||
cursor:default;
|
||||
}
|
||||
|
||||
.band-profile-nav a.last {
|
||||
margin-right:0px !important;
|
||||
}
|
||||
|
||||
.avatar-profile {
|
||||
float:left;
|
||||
padding:2px;
|
||||
width:88px;
|
||||
height:88px;
|
||||
background-color:#ed3618;
|
||||
-webkit-border-radius:44px;
|
||||
-moz-border-radius:44px;
|
||||
border-radius:44px;
|
||||
}
|
||||
|
||||
.avatar-profile img {
|
||||
width:88px;
|
||||
height:88px;
|
||||
-webkit-border-radius:44px;
|
||||
-moz-border-radius:44px;
|
||||
border-radius:44px;
|
||||
}
|
||||
|
||||
.band-profile-wrapper {
|
||||
padding:10px 25px 10px 25px;
|
||||
font-size:15px;
|
||||
color:#ccc;
|
||||
border-bottom: dotted 1px #444;
|
||||
position:relative;
|
||||
display:block;
|
||||
|
||||
.result-name {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 2px;
|
||||
padding-right:4px;
|
||||
.radio-field {
|
||||
display: inline;
|
||||
padding: 2px;
|
||||
margin: 0.5em 2em 0.5em 0.25em;
|
||||
label {
|
||||
display: inline;
|
||||
padding: 2px;
|
||||
}
|
||||
.stats {
|
||||
margin-top: 4px;
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.lcol {
|
||||
width: 200px;
|
||||
}
|
||||
.whitespace {
|
||||
// equal to lcol width.
|
||||
padding-left: 200px;
|
||||
}
|
||||
.instruments {
|
||||
width:128px;
|
||||
img {
|
||||
height:24px;
|
||||
width:24px;
|
||||
margin-right:2px;
|
||||
.iradio-inline {
|
||||
display: inline-block;
|
||||
//padding: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right:0px;
|
||||
|
||||
|
||||
.band-setup-genres {
|
||||
width:100%;
|
||||
height:200px;
|
||||
background-color:#c5c5c5;
|
||||
border:none;
|
||||
-webkit-box-shadow: inset 2px 2px 3px 0px #888;
|
||||
box-shadow: inset 2px 2px 3px 0px #888;
|
||||
color:#000;
|
||||
overflow:auto;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
.band-setup-photo {
|
||||
|
||||
.avatar-space {
|
||||
color: $color2;
|
||||
margin: 20px;
|
||||
position:relative;
|
||||
min-height:300px;
|
||||
|
||||
img.preview_profile_avatar {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.spinner-large {
|
||||
width:300px;
|
||||
height:300px;
|
||||
line-height: 300px;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index: 2000; // to win over jcrop
|
||||
}
|
||||
|
||||
.no-avatar-space {
|
||||
border:1px dotted $color2;
|
||||
|
||||
color: $color2;
|
||||
width:300px;
|
||||
height:300px;
|
||||
line-height: 300px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
background-color:$ColorTextBoxBackground;
|
||||
|
||||
}
|
||||
}
|
||||
.button-row {
|
||||
margin-top:10px;
|
||||
margin-bottom:5px;
|
||||
.result-list-button-wrapper {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.band-profile-header {
|
||||
padding:20px;
|
||||
height:120px;
|
||||
}
|
||||
|
||||
.band-profile-header h2 {
|
||||
font-weight:200;
|
||||
font-size: 28px;
|
||||
float:left;
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
|
||||
.band-profile-status {
|
||||
font-size:12px;
|
||||
float:left;
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
line-height:30px;
|
||||
}
|
||||
|
||||
.band-profile-photo {
|
||||
height: 95px;
|
||||
width: 15%;
|
||||
float:left;
|
||||
}
|
||||
|
||||
.band-profile-nav {
|
||||
width:85%;
|
||||
position:relative;
|
||||
float:right;
|
||||
margin-right:-10px;
|
||||
}
|
||||
|
||||
.band-profile-nav a {
|
||||
width:24%;
|
||||
text-align:center;
|
||||
height: 27px;
|
||||
display: block;
|
||||
float:left;
|
||||
margin-right:5px;
|
||||
vertical-align:bottom;
|
||||
padding-top:65px;
|
||||
background-color:#535353;
|
||||
color:#ccc;
|
||||
font-size:16px;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.band-profile-nav a:hover {
|
||||
background-color:#666;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.band-profile-nav a.active {
|
||||
background-color:#ed3618;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.band-profile-nav a.active:hover {
|
||||
background-color:#ed3618;
|
||||
cursor:default;
|
||||
}
|
||||
|
||||
.band-profile-nav a.last {
|
||||
margin-right:0px !important;
|
||||
}
|
||||
|
||||
.band-avatar-profile {
|
||||
padding:2px;
|
||||
width:88px;
|
||||
height:88px;
|
||||
background-color:#ed3618;
|
||||
-webkit-border-radius:44px;
|
||||
-moz-border-radius:44px;
|
||||
border-radius:44px;
|
||||
}
|
||||
|
||||
.band-avatar-profile img {
|
||||
width:88px;
|
||||
height:88px;
|
||||
-webkit-border-radius:44px;
|
||||
-moz-border-radius:44px;
|
||||
border-radius:44px;
|
||||
}
|
||||
|
||||
|
||||
.band-entry {
|
||||
.item-caption {
|
||||
font-size: 1.4em;
|
||||
font-weight: bold;
|
||||
margin: 0.25em 0em 0.25em 0em;
|
||||
}
|
||||
}
|
||||
|
||||
.band-profile-about-left {
|
||||
width:16%;
|
||||
float:left;
|
||||
font-size:13px;
|
||||
line-height:140%;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.band-profile-about-left h3 {
|
||||
color:#fff;
|
||||
margin-bottom:0px;
|
||||
font-size:13px;
|
||||
font-weight:bold;
|
||||
display:inline;
|
||||
}
|
||||
|
||||
.band-profile-about-right {
|
||||
float:right;
|
||||
font-size:13px;
|
||||
width:84%;
|
||||
line-height:140%;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.band-profile-about-right .band-profile-instrument {
|
||||
text-align:center;
|
||||
margin-right:15px;
|
||||
float:left;
|
||||
}
|
||||
|
||||
.proficiency-beginner {
|
||||
font-size:10px;
|
||||
color:#8ea415;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.proficiency-intermediate {
|
||||
font-size:10px;
|
||||
color:#0b6672;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.proficiency-expert {
|
||||
font-size:10px;
|
||||
color:#ed3618;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.band-profile-members {
|
||||
width:100%;
|
||||
min-height:90px;
|
||||
background-color:#242323;
|
||||
position:relative;
|
||||
float:left;
|
||||
margin:10px 20px 10px 0px;
|
||||
padding-bottom:5px;
|
||||
}
|
||||
|
||||
.band-profile-member-name {
|
||||
float:left;
|
||||
font-size:12px;
|
||||
margin-top:12px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.band-profile-member-location {
|
||||
font-size:12px;
|
||||
font-weight:200;
|
||||
}
|
||||
|
||||
.band-profile-member-genres {
|
||||
float:left;
|
||||
width:40%;
|
||||
font-size:10px;
|
||||
margin-left:10px;
|
||||
padding-right:5px;
|
||||
}
|
||||
|
||||
.band-profile-social-left {
|
||||
float:left;
|
||||
width:32%;
|
||||
margin-right:12px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.band-profile-social-mid {
|
||||
float:left;
|
||||
width:31%;
|
||||
margin-right:12px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.band-profile-social-right {
|
||||
float:left;
|
||||
width:31%;
|
||||
}
|
||||
|
||||
.band-profile-social-left h2, .band-profile-social-mid h2, .band-profile-social-right h2 {
|
||||
font-weight:200;
|
||||
color:#fff;
|
||||
font-size:20px;
|
||||
}
|
||||
|
||||
.band-profile-block {
|
||||
clear:left;
|
||||
white-space:nowrap;
|
||||
display:block;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.band-profile-outer-block {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.band-profile-block-name {
|
||||
display:inline-block;
|
||||
margin-top:13px;
|
||||
font-size:14px;
|
||||
color:#fff;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.band-profile-block-city {
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
#band-filter-results {
|
||||
margin: 0 10px 5px 10px;
|
||||
}
|
||||
|
||||
.band-list-result {
|
||||
padding-top: 5px;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.band-wrapper {
|
||||
overflow: auto;
|
||||
height: 480px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#band-setup-form {
|
||||
.easydropdown {
|
||||
padding: 0 3px;
|
||||
width:100%;
|
||||
.item-content {
|
||||
font-size: 1.1em;
|
||||
margin: 0.25em 0em 0.25em 0em;
|
||||
}
|
||||
margin: 0em 0em 1.5em 0em;
|
||||
}
|
||||
|
||||
.easydropdown-wrapper {
|
||||
width:80%;
|
||||
// .band-name, .band-photo {
|
||||
// display: inline;
|
||||
// }
|
||||
|
||||
.band-profile-wrapper {
|
||||
padding:10px 25px 10px 25px;
|
||||
font-size:15px;
|
||||
color:#ccc;
|
||||
border-bottom: dotted 1px #444;
|
||||
position:relative;
|
||||
display:block;
|
||||
|
||||
.result-name {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 2px;
|
||||
padding-right:4px;
|
||||
}
|
||||
.stats {
|
||||
margin-top: 4px;
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.lcol {
|
||||
width: 200px;
|
||||
}
|
||||
.whitespace {
|
||||
// equal to lcol width.
|
||||
padding-left: 200px;
|
||||
}
|
||||
.instruments {
|
||||
width:128px;
|
||||
img {
|
||||
height:24px;
|
||||
width:24px;
|
||||
margin-right:2px;
|
||||
|
||||
&:last-child {
|
||||
margin-right:0px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.button-row {
|
||||
margin-top:10px;
|
||||
margin-bottom:5px;
|
||||
.result-list-button-wrapper {
|
||||
margin:0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.field {
|
||||
margin: 10px;
|
||||
.band-profile-about-left {
|
||||
width:16%;
|
||||
float:left;
|
||||
font-size:13px;
|
||||
line-height:140%;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.band-profile-about-left h3 {
|
||||
color:#fff;
|
||||
margin-bottom:0px;
|
||||
font-size:13px;
|
||||
font-weight:bold;
|
||||
display:inline;
|
||||
}
|
||||
|
||||
.band-profile-about-right {
|
||||
float:right;
|
||||
font-size:13px;
|
||||
width:84%;
|
||||
line-height:140%;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.band-profile-about-right .band-profile-instrument {
|
||||
text-align:center;
|
||||
margin-right:15px;
|
||||
float:left;
|
||||
}
|
||||
|
||||
.proficiency-beginner {
|
||||
font-size:10px;
|
||||
color:#8ea415;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.proficiency-intermediate {
|
||||
font-size:10px;
|
||||
color:#0b6672;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.proficiency-expert {
|
||||
font-size:10px;
|
||||
color:#ed3618;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.band-profile-members {
|
||||
width:100%;
|
||||
min-height:90px;
|
||||
background-color:#242323;
|
||||
position:relative;
|
||||
float:left;
|
||||
margin:10px 20px 10px 0px;
|
||||
padding-bottom:5px;
|
||||
}
|
||||
|
||||
.band-profile-member-name {
|
||||
float:left;
|
||||
font-size:12px;
|
||||
margin-top:12px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.band-profile-member-location {
|
||||
font-size:12px;
|
||||
font-weight:200;
|
||||
}
|
||||
|
||||
.band-profile-member-genres {
|
||||
float:left;
|
||||
width:40%;
|
||||
font-size:10px;
|
||||
margin-left:10px;
|
||||
padding-right:5px;
|
||||
}
|
||||
|
||||
.band-profile-social-left {
|
||||
float:left;
|
||||
width:32%;
|
||||
margin-right:12px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.band-profile-social-mid {
|
||||
float:left;
|
||||
width:31%;
|
||||
margin-right:12px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.band-profile-social-right {
|
||||
float:left;
|
||||
width:31%;
|
||||
}
|
||||
|
||||
.band-profile-social-left h2, .band-profile-social-mid h2, .band-profile-social-right h2 {
|
||||
font-weight:200;
|
||||
color:#fff;
|
||||
font-size:20px;
|
||||
}
|
||||
|
||||
.band-profile-block {
|
||||
clear:left;
|
||||
white-space:nowrap;
|
||||
display:block;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.band-profile-outer-block {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.band-profile-block-name {
|
||||
display:inline-block;
|
||||
margin-top:13px;
|
||||
font-size:14px;
|
||||
color:#fff;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.band-profile-block-city {
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
#band-filter-results {
|
||||
margin: 0 10px 5px 10px;
|
||||
}
|
||||
|
||||
.band-list-result {
|
||||
padding-top: 5px;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.band-wrapper {
|
||||
overflow: auto;
|
||||
height: 480px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
#band-setup-form {
|
||||
margin: 0.25em 0.5em 1.25em 0.25em;
|
||||
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 {
|
||||
padding: 0 3px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.easydropdown-wrapper {
|
||||
width:80%;
|
||||
}
|
||||
|
||||
div.field {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-bottom:2px;
|
||||
}
|
||||
|
||||
#desired-experience-label {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.band-setup-genre {
|
||||
input {
|
||||
display: inline;
|
||||
width: auto !important;
|
||||
}
|
||||
label {
|
||||
display: inline;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
margin-bottom:2px;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
|
||||
label.strong-label {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -32,6 +32,9 @@
|
|||
*= require ./findSession
|
||||
*= require ./session
|
||||
*= require ./account
|
||||
*= require ./accountProfileExperience
|
||||
*= require ./accountProfileInterests
|
||||
*= require ./accountProfileSamples
|
||||
*= require ./accountPaymentHistory
|
||||
*= require ./account_affiliate
|
||||
*= require ./search
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@
|
|||
|
||||
.button-row {
|
||||
float:none;
|
||||
.result-list-button-wrapper {
|
||||
margin:3px;
|
||||
}
|
||||
}
|
||||
|
||||
.latency-holder {
|
||||
|
|
@ -138,6 +141,95 @@
|
|||
#musician-filter-results {
|
||||
margin: 0 10px 0px 10px;
|
||||
}
|
||||
|
||||
#musician-search-filter-results-header {
|
||||
padding: 10px 10px 10px 10px;
|
||||
}
|
||||
|
||||
#btn-musician-search-builder {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#musician-search-filter-description {
|
||||
padding: 5px 5px 5px 5px;
|
||||
display: inline;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#btn-musician-search-reset {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#musician-search-filter-results-list-blank {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin: 30px 10px 10px 10px;
|
||||
}
|
||||
|
||||
#musician-search-filter-spinner {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.col-left {
|
||||
float: left;
|
||||
width: 50%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.col-right {
|
||||
float: right;
|
||||
width: 50%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.builder-section {
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.builder-button {
|
||||
float: right;
|
||||
}
|
||||
.band-setup-genres {
|
||||
width: 80%;
|
||||
}
|
||||
.easydropdown-wrapper {
|
||||
width: 80%;
|
||||
}
|
||||
.builder-sort-order {
|
||||
text-align: right;
|
||||
.easydropdown-wrapper {
|
||||
width: 140px;
|
||||
}
|
||||
.text-label {
|
||||
vertical-align: top;
|
||||
margin-right: 5px;
|
||||
display: inline;
|
||||
line-height: 2em;
|
||||
}
|
||||
.select {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.builder-ages {
|
||||
width: 100%;
|
||||
}
|
||||
.builder-instruments {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
}
|
||||
.builder-selector {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.builder-action-buttons {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.filter-element {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@import "client/common.css.scss";
|
||||
|
||||
#user-profile {
|
||||
#user-profile, #band-profile {
|
||||
.profile-about-right {
|
||||
|
||||
textarea {
|
||||
|
|
@ -9,32 +9,69 @@
|
|||
padding:0;
|
||||
}
|
||||
}
|
||||
|
||||
div.logo, div.item {
|
||||
text-align: bottom;
|
||||
}
|
||||
|
||||
.online-presence-option, .performance-sample-option {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
img.logo {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin:0px 0px 10px 0px;
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-left: 15px;
|
||||
margin-bottom: 0px !important;
|
||||
list-style: disc;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-head {
|
||||
|
||||
}
|
||||
.profile-body {
|
||||
|
||||
|
||||
}
|
||||
.profile-header {
|
||||
padding:10px 20px;
|
||||
// height:120px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.profile-header h2 {
|
||||
font-weight:200;
|
||||
font-size: 28px;
|
||||
float:left;
|
||||
margin: 0px 150px 0px 0px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
}
|
||||
|
||||
.profile-status {
|
||||
.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 {
|
||||
font-size:12px;
|
||||
float:left;
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
line-height:30px;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.profile-photo {
|
||||
|
|
@ -159,7 +196,7 @@
|
|||
font-weight:600;
|
||||
}
|
||||
|
||||
#profile-bands .when-empty {
|
||||
#bands-content .when-empty {
|
||||
margin: 0px;
|
||||
padding:0px;
|
||||
display:block;
|
||||
|
|
@ -170,7 +207,7 @@
|
|||
line-height: 150%;
|
||||
}
|
||||
|
||||
#profile-bands .when-empty a {
|
||||
#bands-content .when-empty a {
|
||||
text-decoration: underline;
|
||||
color: inherit;
|
||||
}
|
||||
|
|
@ -205,18 +242,6 @@
|
|||
padding-right:5px;
|
||||
}
|
||||
|
||||
.user-setup-genres {
|
||||
width:40%;
|
||||
height:90px;
|
||||
background-color:#c5c5c5;
|
||||
border:none;
|
||||
-webkit-box-shadow: inset 2px 2px 3px 0px #888;
|
||||
box-shadow: inset 2px 2px 3px 0px #888;
|
||||
color:#000;
|
||||
overflow:auto;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.profile-band-list-result {
|
||||
width:100%;
|
||||
min-height:85px;
|
||||
|
|
@ -228,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;
|
||||
|
|
@ -254,11 +279,11 @@
|
|||
height:24px;
|
||||
width:24px;
|
||||
margin-right:2px;
|
||||
|
||||
|
||||
&:last-child {
|
||||
margin-right:0px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
.button-row {
|
||||
|
|
@ -330,14 +355,14 @@
|
|||
display:none;
|
||||
}
|
||||
|
||||
#profile-history {
|
||||
#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;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 5px 5px 5px 30px;
|
||||
|
||||
float: left;
|
||||
}
|
||||
.validate-checkmark {
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
display:inline-block;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
margin-top: -40px;
|
||||
margin-top: -10px;
|
||||
left: 0px;
|
||||
}
|
||||
.error {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
@import "client/common";
|
||||
|
||||
#genre-selector-dialog {
|
||||
|
||||
min-height:initial;
|
||||
|
||||
.dialog-inner {
|
||||
display:block;
|
||||
overflow:auto;
|
||||
max-height:300px;
|
||||
color:white;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.three-column-list-container {
|
||||
-moz-column-count: 3;
|
||||
-moz-column-gap: 10px;
|
||||
-webkit-column-count: 3;
|
||||
-webkit-column-gap: 10px;
|
||||
column-count: 3;
|
||||
column-gap: 10px;
|
||||
margin-left: 0;
|
||||
ul {
|
||||
list-style-type: none;
|
||||
li {
|
||||
margin: 1px 4px 1px 0;
|
||||
font-size:12px;
|
||||
line-height:14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.genres {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
@import "client/common";
|
||||
|
||||
#instrument-selector-dialog {
|
||||
|
||||
min-height:initial;
|
||||
|
||||
|
||||
.dialog-inner {
|
||||
.content-body {
|
||||
max-height: auto;
|
||||
.content-body-scroller {
|
||||
height: 350px;
|
||||
overflow: scroll;
|
||||
background-color:#c5c5c5;
|
||||
border: 1px inset;
|
||||
}
|
||||
border: 1px solid #222;
|
||||
margin: 4px 4px 8px 4px;
|
||||
}
|
||||
|
||||
.instructions {
|
||||
font-size:16px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
box-shadow:0 0 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.instruments {
|
||||
|
||||
}
|
||||
|
||||
label {
|
||||
display:inline;
|
||||
color: black;
|
||||
font-size:16px;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
@import "client/common";
|
||||
|
||||
#recording-selector-dialog {
|
||||
|
||||
min-height:initial;
|
||||
|
||||
.dialog-inner {
|
||||
color:white;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin-bottom:10px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#sound-cloud-player-dialog {
|
||||
height:auto;
|
||||
.caption {
|
||||
margin: 0.1em 0.1em 0.5em 0em
|
||||
}
|
||||
}
|
||||
|
|
@ -250,6 +250,7 @@ class ApiBandsController < ApiController
|
|||
def auth_band_member
|
||||
@band = Band.find(params[:id])
|
||||
unless @band.users.exists? current_user
|
||||
Rails.logger.info("Could not find #{current_user} in #{@band.users.inspect}")
|
||||
raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR
|
||||
end
|
||||
end
|
||||
|
|
@ -257,6 +258,7 @@ class ApiBandsController < ApiController
|
|||
uid = current_user.id
|
||||
@band = Band.find(params[:id])
|
||||
unless @band.band_musicians.detect { |bm| bm.user_id == uid && bm.admin? }
|
||||
Rails.logger.info("Could not find #{current_user} in #{@band.band_musicians.inspect}")
|
||||
raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,4 +21,27 @@ class ApiSearchController < ApiController
|
|||
@search = Search.text_search(params, current_user)
|
||||
end
|
||||
end
|
||||
|
||||
def musicians
|
||||
if request.get?
|
||||
if params[:results]
|
||||
@search = MusicianSearch.user_search_filter(current_user).search_results_page
|
||||
respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index'
|
||||
else
|
||||
render :json => MusicianSearch.search_filter_json(current_user), :status => 200
|
||||
end
|
||||
|
||||
elsif request.post?
|
||||
ms = MusicianSearch.user_search_filter(current_user)
|
||||
filter = params[:filter]
|
||||
if filter == 'reset'
|
||||
@search = ms.reset_search_results
|
||||
else
|
||||
json = JSON.parse(filter, :create_additions => false)
|
||||
@search = ms.search_results_page(json, [params[:page].to_i, 1].max)
|
||||
end
|
||||
respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/index'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32,6 +32,17 @@ class ApiUsersController < ApiController
|
|||
respond_with @user, responder: ApiResponder, :status => 200
|
||||
end
|
||||
|
||||
def profile_show
|
||||
@profile = User.includes([{musician_instruments: :instrument},
|
||||
{band_musicians: :user},
|
||||
{genre_players: :genre},
|
||||
:bands, :instruments, :genres,
|
||||
:online_presences, :performance_samples])
|
||||
.find(params[:id])
|
||||
|
||||
respond_with @profile, responder: ApiResponder, :status => 200
|
||||
end
|
||||
|
||||
# in other words, a minimal signup
|
||||
def create
|
||||
# today, this only accepts a minimal registration; it could be made to take in more if we wanted
|
||||
|
|
@ -69,7 +80,10 @@ class ApiUsersController < ApiController
|
|||
respond_with_model(@user, new: true, location: lambda { return api_user_detail_url(@user.id) })
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def profile_save
|
||||
end
|
||||
|
||||
def update
|
||||
|
||||
@user = User.find(params[:id])
|
||||
|
|
@ -82,11 +96,46 @@ class ApiUsersController < ApiController
|
|||
@user.country = params[:country] if params.has_key?(:country)
|
||||
@user.musician = params[:musician] if params.has_key?(:musician)
|
||||
@user.update_instruments(params[:instruments].nil? ? [] : params[:instruments]) if params.has_key?(:instruments)
|
||||
@user.update_genres(params[:genres].nil? ? [] : params[:genres]) if params.has_key?(:genres)
|
||||
|
||||
# genres
|
||||
@user.update_genres(params[:genres].nil? ? [] : params[:genres], GenrePlayer::PROFILE) if params.has_key?(:genres)
|
||||
@user.update_genres(params[:virtual_band_genres].nil? ? [] : params[:virtual_band_genres], GenrePlayer::VIRTUAL_BAND) if params.has_key?(:virtual_band_genres)
|
||||
@user.update_genres(params[:traditional_band_genres].nil? ? [] : params[:traditional_band_genres], GenrePlayer::TRADITIONAL_BAND) if params.has_key?(:traditional_band_genres)
|
||||
@user.update_genres(params[:paid_session_genres].nil? ? [] : params[:paid_session_genres], GenrePlayer::PAID_SESSION) if params.has_key?(:paid_session_genres)
|
||||
@user.update_genres(params[:free_session_genres].nil? ? [] : params[:free_session_genres], GenrePlayer::FREE_SESSION) if params.has_key?(:free_session_genres)
|
||||
@user.update_genres(params[:cowriting_genres].nil? ? [] : params[:cowriting_genres], GenrePlayer::COWRITING) if params.has_key?(:cowriting_genres)
|
||||
|
||||
@user.show_whats_next = params[:show_whats_next] if params.has_key?(:show_whats_next)
|
||||
@user.show_whats_next_count = params[:show_whats_next_count] if params.has_key?(:show_whats_next_count)
|
||||
@user.subscribe_email = params[:subscribe_email] if params.has_key?(:subscribe_email)
|
||||
@user.biography = params[:biography] if params.has_key?(:biography)
|
||||
|
||||
@user.website = params[:website] if params.has_key?(:website)
|
||||
@user.skill_level = params[:skill_level] if params.has_key?(:skill_level)
|
||||
@user.concert_count = params[:concert_count] if params.has_key?(:concert_count)
|
||||
@user.studio_session_count = params[:studio_session_count] if params.has_key?(:studio_session_count)
|
||||
|
||||
# virtual band
|
||||
@user.virtual_band = params[:virtual_band] if params.has_key?(:virtual_band)
|
||||
@user.virtual_band_commitment = params[:virtual_band_commitment] if params.has_key?(:virtual_band_commitment)
|
||||
|
||||
# traditional band
|
||||
@user.traditional_band = params[:traditional_band] if params.has_key?(:traditional_band)
|
||||
@user.traditional_band_commitment = params[:traditional_band_commitment] if params.has_key?(:traditional_band_commitment)
|
||||
@user.traditional_band_touring = params[:traditional_band_touring] if params.has_key?(:traditional_band_touring)
|
||||
|
||||
# paid sessions
|
||||
@user.paid_sessions = params[:paid_sessions] if params.has_key?(:paid_sessions)
|
||||
@user.paid_sessions_hourly_rate = params[:paid_sessions_hourly_rate] if params.has_key?(:paid_sessions_hourly_rate)
|
||||
@user.paid_sessions_daily_rate = params[:paid_sessions_daily_rate] if params.has_key?(:paid_sessions_daily_rate)
|
||||
|
||||
# free sessions
|
||||
@user.free_sessions = params[:free_sessions] if params.has_key?(:free_sessions)
|
||||
|
||||
# co-writing
|
||||
@user.cowriting = params[:cowriting] if params.has_key?(:cowriting)
|
||||
@user.cowriting_purpose = params[:cowriting_purpose] if params.has_key?(:cowriting_purpose)
|
||||
|
||||
@user.want_jamblaster = params[:want_jamblaster] if params.has_key?(:want_jamblaster)
|
||||
@user.mod_merge(params[:mods]) if params[:mods]
|
||||
|
||||
|
|
@ -95,6 +144,9 @@ class ApiUsersController < ApiController
|
|||
@user.update_notification_seen_at params[:notification_seen_at]
|
||||
end
|
||||
|
||||
@user.update_online_presences(params[:online_presences]) if params.has_key?(:online_presences)
|
||||
@user.update_performance_samples(params[:performance_samples]) if params.has_key?(:performance_samples)
|
||||
|
||||
@user.save
|
||||
|
||||
if @user.errors.any?
|
||||
|
|
@ -782,9 +834,9 @@ class ApiUsersController < ApiController
|
|||
if site.blank? || 'url'==site
|
||||
url = data
|
||||
elsif Utils.recording_source?(site)
|
||||
rec_id = Utils.extract_recording_id(site, data)
|
||||
if rec_id
|
||||
render json: { message: 'Valid Site', recording_id: rec_id, data: data }, status: 200
|
||||
rec_data = Utils.extract_recording_data(site, data)
|
||||
if rec_data
|
||||
render json: { message: 'Valid Site', recording_id: rec_data["id"], recording_title: rec_data["title"], data: data }, status: 200
|
||||
return
|
||||
else
|
||||
render json: { message: 'Invalid Site', data: data, errors: { site: ["Could not detect recording identifier"] } }, status: 200
|
||||
|
|
|
|||
|
|
@ -67,4 +67,10 @@ class SpikesController < ApplicationController
|
|||
def recording_source
|
||||
render :layout => 'web'
|
||||
end
|
||||
|
||||
def musician_search_filter
|
||||
# gon.musician_search_meta = MusicianSearch::SEARCH_FILTER_META
|
||||
render :layout => 'web'
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -402,12 +402,14 @@ JS
|
|||
redirect_to '/'
|
||||
end if params[:user_token].present?
|
||||
|
||||
if request.get?
|
||||
#if request.get?
|
||||
|
||||
elsif request.post?
|
||||
#elsif request.post?
|
||||
@user.subscribe_email = false
|
||||
@user.save!
|
||||
end
|
||||
#end
|
||||
|
||||
render text: 'You have been unsubscribed.'
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ module ClientHelper
|
|||
gon.ftue_network_test_duration = Rails.application.config.ftue_network_test_duration
|
||||
gon.ftue_network_test_max_clients = Rails.application.config.ftue_network_test_max_clients
|
||||
gon.ftue_maximum_gear_latency = Rails.application.config.ftue_maximum_gear_latency
|
||||
gon.musician_search_meta = MusicianSearch::SEARCH_FILTER_META
|
||||
|
||||
# is this the native client or browser?
|
||||
@nativeClient = is_native_client?
|
||||
|
|
@ -77,4 +78,4 @@ module ClientHelper
|
|||
gon.use_cached_session_scores = Rails.application.config.use_cached_session_scores
|
||||
gon.allow_both_find_algos = Rails.application.config.allow_both_find_algos
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
object @band
|
||||
|
||||
attributes :id, :name, :city, :state, :country, :location, :website, :biography, :photo_url, :logo_url, :liker_count, :follower_count, :recording_count, :session_count,
|
||||
:original_fpfile_photo, :cropped_fpfile_photo, :crop_selection_photo
|
||||
:original_fpfile_photo, :cropped_fpfile_photo, :crop_selection_photo,
|
||||
:band_type, :band_status, :concert_count, :add_new_members, :play_commitment, :touring_option, :paid_gigs,
|
||||
:free_gigs, :hourly_rate, :gig_minimum
|
||||
|
||||
child :users => :musicians do
|
||||
attributes :id, :first_name, :last_name, :name, :photo_url
|
||||
|
|
@ -16,11 +18,27 @@ child :users => :musicians do
|
|||
end
|
||||
end
|
||||
|
||||
child :instruments => :instruments do
|
||||
attributes :id, :instrument_id, :proficiency_level
|
||||
end
|
||||
|
||||
child :genres => :genres do
|
||||
attributes :id, :description
|
||||
#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)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
object @claimed_recording
|
||||
|
||||
attributes :id, :name, :description, :is_public, :genre_id, :discarded
|
||||
attributes :id, :user_id, :name, :description, :is_public, :genre_id, :discarded
|
||||
|
||||
node :share_url do |claimed_recording|
|
||||
unless claimed_recording.share_token.nil?
|
||||
|
|
@ -20,7 +20,7 @@ node :mix do |claimed_recording|
|
|||
end
|
||||
|
||||
child(:recording => :recording) {
|
||||
attributes :id, :created_at, :duration, :comment_count, :like_count, :play_count, :jam_track_id, :jam_track_initiator_id
|
||||
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :has_mix?, :mix_state, :when_will_be_discarded?, :jam_track_id, :jam_track_initiator_id
|
||||
|
||||
node :timeline do |recording|
|
||||
recording.timeline ? JSON.parse(recording.timeline) : {}
|
||||
|
|
@ -78,4 +78,20 @@ child(:recording => :recording) {
|
|||
attributes :id, :first_name, :last_name, :name, :photo_url, :musician
|
||||
}
|
||||
}
|
||||
|
||||
node do |recording|
|
||||
{
|
||||
helpers: {
|
||||
avatar: asset_path(resolve_avatarables(recording.band, recording.owner)),
|
||||
artist_name: recording_artist_name(recording),
|
||||
artist_id: recording_artist_id(recording),
|
||||
artist_hoveraction: recording_artist_hoveraction(recording),
|
||||
artist_datakey: recording_artist_datakey(recording),
|
||||
utc_created_at: recording.created_at.getutc.iso8601,
|
||||
name: recording_name(recording, current_user),
|
||||
description: recording_description(recording, current_user),
|
||||
genre: recording_genre(recording)
|
||||
}
|
||||
}
|
||||
end
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ glue :recording do
|
|||
'recording'
|
||||
end
|
||||
|
||||
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :has_mix?, :mix_state, :when_will_be_discarded?
|
||||
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count, :has_mix?, :mix_state, :when_will_be_discarded?
|
||||
|
||||
node do |recording|
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,64 @@ object @search
|
|||
|
||||
node :search_type do |ss| ss.search_type end
|
||||
|
||||
if @search.is_a?(MusicianSearch)
|
||||
|
||||
node :page_count do |foo|
|
||||
@search.page_count
|
||||
end
|
||||
|
||||
node :my_audio_latency do |user|
|
||||
current_user.last_jam_audio_latency.round if current_user.last_jam_audio_latency
|
||||
end
|
||||
|
||||
node :is_blank_filter do |foo|
|
||||
@search.is_blank?
|
||||
end
|
||||
|
||||
node :filter_json do |foo|
|
||||
@search.to_json
|
||||
end
|
||||
|
||||
child(:results => :musicians) {
|
||||
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :online, :musician, :photo_url, :biography, :regionname, :score, :full_score
|
||||
|
||||
node :is_friend do |musician|
|
||||
@search.is_friend?(musician)
|
||||
end
|
||||
|
||||
node :is_following do |musician|
|
||||
@search.is_follower?(musician)
|
||||
end
|
||||
|
||||
node :pending_friend_request do |musician|
|
||||
musician.pending_friend_request?(current_user)
|
||||
end
|
||||
|
||||
node :biography do |musician|
|
||||
musician.biography.nil? ? "" : musician.biography
|
||||
end
|
||||
|
||||
child :musician_instruments => :instruments do
|
||||
attributes :instrument_id, :description, :proficiency_level, :priority
|
||||
end
|
||||
|
||||
child :top_followings => :followings do |uf|
|
||||
node :user_id do |uu| uu.id end
|
||||
node :photo_url do |uu| uu.photo_url end
|
||||
node :name do |uu| uu.name end
|
||||
end
|
||||
|
||||
node :follow_count do |musician| @search.follow_count(musician) end
|
||||
node :friend_count do |musician| @search.friend_count(musician) end
|
||||
node :recording_count do |musician| @search.record_count(musician) end
|
||||
node :session_count do |musician| @search.session_count(musician) end
|
||||
|
||||
node :audio_latency do |musician|
|
||||
last_jam_audio_latency(musician)
|
||||
end
|
||||
}
|
||||
else
|
||||
|
||||
if @search.session_invite_search?
|
||||
child(:results => :suggestions) {
|
||||
node :value do |uu| uu.name end
|
||||
|
|
@ -43,6 +101,14 @@ if @search.musicians_filter_search?
|
|||
current_user.last_jam_audio_latency.round if current_user.last_jam_audio_latency
|
||||
end
|
||||
|
||||
node :is_blank_filter do |foo|
|
||||
@search.is_blank?
|
||||
end
|
||||
|
||||
node :filter_json do |foo|
|
||||
@search.to_json
|
||||
end
|
||||
|
||||
child(:results => :musicians) {
|
||||
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :online, :musician, :photo_url, :biography, :regionname, :score, :full_score
|
||||
|
||||
|
|
@ -131,3 +197,4 @@ if @search.fans_text_search?
|
|||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
collection @users
|
||||
|
||||
# do not retrieve all child collections when showing a list of users
|
||||
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url, :biography
|
||||
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url, :biography, :age, :website, :skill_level, :concert_count, :studio_session_count, :virtual_band, :virtual_band_commitment, :traditional_band, :traditional_band_commitment, :traditional_band_touring, :paid_sessions, :paid_sessions_hourly_rate,
|
||||
:paid_sessions_daily_rate, :free_sessions, :cowriting, :cowriting_purpose
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
object @profile
|
||||
|
||||
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :follower_count, :following_count, :recording_count, :session_count, :biography, :favorite_count, :audio_latency, :upcoming_session_count, :age, :website, :skill_level, :concert_count, :studio_session_count, :virtual_band, :virtual_band_commitment, :traditional_band, :traditional_band_commitment, :traditional_band_touring, :paid_sessions, :paid_sessions_hourly_rate,
|
||||
:paid_sessions_daily_rate, :free_sessions, :cowriting, :cowriting_purpose, :subscribe_email
|
||||
|
||||
child :online_presences => :online_presences do
|
||||
attributes :id, :service_type, :username
|
||||
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 :genre_players => :genres do
|
||||
attributes :genre_id, :player_type, :genre_type
|
||||
end
|
||||
|
||||
child :band_musicians => :bands do
|
||||
attributes :id, :name, :admin, :photo_url, :logo_url
|
||||
|
||||
child :genres => :genres do
|
||||
attributes :id, :description
|
||||
#partial('api_genres/index', :object => @user.bands.genres)
|
||||
end
|
||||
end
|
||||
|
||||
child :musician_instruments => :instruments do
|
||||
attributes :description, :proficiency_level, :priority, :instrument_id
|
||||
end
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
object @user
|
||||
|
||||
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :follower_count, :following_count, :recording_count, :session_count, :biography, :favorite_count, :audio_latency, :upcoming_session_count
|
||||
attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :follower_count, :following_count,
|
||||
:recording_count, :session_count, :biography, :favorite_count, :audio_latency, :upcoming_session_count, :age, :website, :skill_level, :reuse_card, :purchased_jamtracks_count
|
||||
|
||||
if @user.musician?
|
||||
node :location do @user.location end
|
||||
|
|
|
|||