merging feature/musician_profile_enhancements
|
|
@ -64,7 +64,7 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
|
|||
|
||||
begin
|
||||
client.find_or_create_account(user, billing_info)
|
||||
client.place_order(user, jam_track)
|
||||
client.place_order(user, jam_track, nil)
|
||||
rescue RecurlyClientError=>x
|
||||
redirect_to admin_jam_track_rights_path, notice: "Could not order #{jam_track} for #{user.to_s}: #{x.errors.inspect}"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
|
|||
|
||||
column :original_artist
|
||||
column :name
|
||||
column :flags do |jam_track| jam_track.duplicate_positions? ? 'DUP POSITIONS' : '' end
|
||||
column :status
|
||||
column :master_track do |jam_track| jam_track.master_track.nil? ? 'None' : (link_to "Download", jam_track.master_track.url_by_sample_rate(44)) end
|
||||
column :licensor
|
||||
|
|
|
|||
|
|
@ -149,9 +149,9 @@ SELECT played.player_id FROM
|
|||
(SELECT player_id, COUNT(*) cnt FROM playable_plays pp
|
||||
WHERE
|
||||
pp.created_at >= '#{start_date}' AND
|
||||
pp.created_at <= '#{end_date}' AND
|
||||
pp.playable_type = 'JamRuby::JamTrack'
|
||||
GROUP BY player_id
|
||||
pp.created_at <= '#{end_date}' AND
|
||||
pp.playable_type = 'JamRuby::JamTrack' /* VRFS-2916 jam_tracks.id is varchar: ADD */
|
||||
GROUP BY player_id
|
||||
) played
|
||||
WHERE #{where}
|
||||
SQL
|
||||
|
|
@ -168,7 +168,10 @@ WHERE
|
|||
tt.created_at >= '#{start_date}' AND
|
||||
tt.created_at <= '#{end_date}'
|
||||
SQL
|
||||
yield(sql) if block_given?
|
||||
if block_given?
|
||||
yield_sql = yield(sql)
|
||||
sql = yield_sql unless yield_sql.blank?
|
||||
end
|
||||
self.class.cohort_users(self).where("users.id IN (#{sql})").count
|
||||
end
|
||||
|
||||
|
|
@ -196,12 +199,12 @@ SQL
|
|||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :jam_track_rights, num_user) do |subsql|
|
||||
subsql += " AND tt.redeemed = 'f' "
|
||||
subsql += " AND tt.is_test_purchase = 'f' AND tt.redeemed = 'f' "
|
||||
end
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :jam_track_rights, num_user) do |subsql|
|
||||
subsql += " AND tt.redeemed = 't' "
|
||||
subsql += " AND tt.is_test_purchase = 'f' AND tt.redeemed = 't' "
|
||||
end
|
||||
_put_data_set(:jam_track_rights_redeemed, count, num_user)
|
||||
|
||||
|
|
@ -235,13 +238,6 @@ SQL
|
|||
self.save!
|
||||
end
|
||||
|
||||
def _join_user_all_time(assoc_ref)
|
||||
assoc_ref.active_record
|
||||
.joins("INNER JOIN users AS uu ON uu.id = #{assoc_ref.foreign_key}")
|
||||
.where(created_at: self.group_start..self.group_end)
|
||||
.where(['uu.created_at >= ? AND uu.created_at <= ?', self.group_start, self.group_end])
|
||||
end
|
||||
|
||||
def _all_time!
|
||||
unless 0 < num_user = self.class.cohort_users(self).count
|
||||
self.update_attribute(:data_set, {})
|
||||
|
|
@ -270,10 +266,15 @@ SQL
|
|||
count = _subquery(assoc_key = :friendships, num_user)
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
count = _subquery(assoc_key = :jam_track_rights, num_user)
|
||||
count = _subquery(assoc_key = :jam_track_rights, num_user) do |subsql|
|
||||
subsql += " AND tt.is_test_purchase = 'f'"
|
||||
end
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
||||
|
||||
count = _subquery(assoc_key = :jam_tracks_played, num_user) do |subsql|
|
||||
# VRFS-2916 jam_tracks.id is varchar: REMOVE
|
||||
# subsql += " AND tt.jam_track_id IS NOT NULL "
|
||||
# VRFS-2916 jam_tracks.id is varchar: ADD
|
||||
subsql += " AND tt.playable_type = 'JamRuby::JamTrack' "
|
||||
end
|
||||
_put_data_set(assoc_key, count, num_user)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
= f.inputs name: 'Jam Track Right fields' do
|
||||
|
||||
ol.nested-fields
|
||||
= f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false
|
||||
= f.input :user, :required=>true, collection: User.all, include_blank: false
|
||||
|
|
@ -68,7 +68,7 @@ class JamRuby::JamTrackTrack
|
|||
|
||||
s3_manager.download(self.url_by_sample_rate(44), input)
|
||||
|
||||
command = "sox \"#{input}\" \"#{output}\" trim #{start} #{stop}"
|
||||
command = "sox \"#{input}\" \"#{output}\" trim #{sprintf("%.3f", start)} =#{sprintf("%.3f", stop)}"
|
||||
|
||||
@@log.debug("trimming using: " + command)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ FactoryGirl.define do
|
|||
state "NC"
|
||||
country "US"
|
||||
terms_of_service true
|
||||
reuse_card true
|
||||
|
||||
|
||||
factory :admin do
|
||||
|
|
|
|||
|
|
@ -270,4 +270,10 @@ preview_jam_track_tracks.sql
|
|||
cohorts.sql
|
||||
jam_track_right_admin_purchase.sql
|
||||
alter_genre_player_unique_constraint.sql
|
||||
jam_track_playable_plays.sql
|
||||
shopping_cart_anonymous.sql
|
||||
user_reuse_card_and_reedem.sql
|
||||
jam_track_id_to_varchar.sql
|
||||
drop_position_unique_jam_track.sql
|
||||
recording_client_metadata.sql
|
||||
musician_search.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
DROP INDEX jam_track_tracks_position_uniqkey;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
-- change jam_tracks PRIMARY KEY to VARCHAR(64)
|
||||
|
||||
-- first, drop all constraints and change the types
|
||||
ALTER TABLE jam_track_tracks DROP CONSTRAINT jam_track_tracks_jam_track_id_fkey;
|
||||
ALTER TABLE jam_track_tracks ALTER COLUMN jam_track_id TYPE VARCHAR(64);
|
||||
ALTER TABLE jam_track_tap_ins DROP CONSTRAINT jam_track_tap_ins_jam_track_id_fkey;
|
||||
ALTER TABLE jam_track_tap_ins ALTER COLUMN jam_track_id TYPE VARCHAR(64);
|
||||
ALTER TABLE jam_track_rights DROP CONSTRAINT jam_track_rights_jam_track_id_fkey;
|
||||
ALTER TABLE jam_track_rights ALTER COLUMN jam_track_id TYPE VARCHAR(64);
|
||||
ALTER TABLE active_music_sessions ALTER COLUMN jam_track_id TYPE VARCHAR(64);
|
||||
ALTER TABLE recordings DROP CONSTRAINT recordings_jam_track_id_fkey;
|
||||
ALTER TABLE recordings ALTER COLUMN jam_track_id TYPE VARCHAR(64);
|
||||
ALTER TABLE playable_plays DROP COLUMN jam_track_id;
|
||||
|
||||
|
||||
-- then drop the jamtrack sequence, change it's type, and then set default to UUID
|
||||
-- DROP SEQUENCE jam_tracks_next_seq;
|
||||
ALTER TABLE jam_tracks ALTER COLUMN id TYPE VARCHAR(64);
|
||||
ALTER TABLE jam_tracks ALTER COLUMN id SET DEFAULT uuid_generate_v4();
|
||||
|
||||
-- add back in all the constraints on the fk tables
|
||||
ALTER TABLE jam_track_tracks ADD CONSTRAINT jam_track_tracks_jam_track_id_fkey FOREIGN KEY (jam_track_id) REFERENCES jam_tracks(id) ON DELETE CASCADE;
|
||||
ALTER TABLE jam_track_tap_ins ADD CONSTRAINT jam_track_tap_ins_jam_track_id_fkey FOREIGN KEY (jam_track_id) REFERENCES jam_tracks(id) ON DELETE CASCADE;
|
||||
ALTER TABLE jam_track_rights ADD CONSTRAINT jam_track_rights_jam_track_id_fkey FOREIGN KEY (jam_track_id) REFERENCES jam_tracks(id);
|
||||
ALTER TABLE recordings ADD CONSTRAINT recordings_jam_track_id_fkey FOREIGN KEY (jam_track_id) REFERENCES jam_tracks(id);
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
ALTER TABLE playable_plays ADD COLUMN jam_track_id bigint;
|
||||
ALTER TABLE playable_plays ALTER COLUMN playable_id DROP NOT NULL;
|
||||
ALTER TABLE playable_plays ALTER COLUMN playable_type DROP NOT NULL;
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE recordings ADD COLUMN timeline JSON;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE shopping_carts ALTER COLUMN user_id DROP NOT NULL;
|
||||
ALTER TABLE shopping_carts ADD COLUMN anonymous_user_id VARCHAR(1000);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE users ADD COLUMN reuse_card BOOLEAN DEFAULT TRUE NOT NULL;
|
||||
ALTER TABLE users ADD COLUMN has_redeemable_jamtrack BOOLEAN DEFAULT TRUE NOT NULL;
|
||||
ALTER TABLE shopping_carts ADD COLUMN marked_for_redeem INTEGER DEFAULT 0 NOT NULL;
|
||||
|
|
@ -7,5 +7,3 @@ Create development database 'jam_ruby'
|
|||
Once you've created your database, migrate it:
|
||||
`bundle exec jam_ruby up`
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ require "jam_ruby/models/max_mind_release"
|
|||
require "jam_ruby/models/genre_player"
|
||||
require "jam_ruby/models/genre"
|
||||
require "jam_ruby/models/user"
|
||||
require "jam_ruby/models/anonymous_user"
|
||||
require "jam_ruby/models/rsvp_request"
|
||||
require "jam_ruby/models/rsvp_slot"
|
||||
require "jam_ruby/models/rsvp_request_rsvp_slot"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ module JamRuby
|
|||
|
||||
class << self
|
||||
|
||||
|
||||
def save_jam_track_jkz(user, jam_track, sample_rate=48)
|
||||
jam_track_right = jam_track.right_for_user(user)
|
||||
raise ArgumentError if jam_track_right.nil?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
# this was added to support the idea of an anonymous user interacting with our site; needed by the ShoppingCart
|
||||
# over time it might make sense to beef this up and to use it conistently in anonymous interactions
|
||||
|
||||
module JamRuby
|
||||
class AnonymousUser
|
||||
|
||||
attr_accessor :id
|
||||
|
||||
def initialize(id)
|
||||
@id = id
|
||||
end
|
||||
|
||||
def shopping_carts
|
||||
ShoppingCart.where(anonymous_user_id: @id)
|
||||
end
|
||||
|
||||
def destroy_all_shopping_carts
|
||||
ShoppingCart.destroy_all(anonymous_user_id: @id)
|
||||
end
|
||||
|
||||
def admin
|
||||
false
|
||||
end
|
||||
|
||||
def has_redeemable_jamtrack
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -44,25 +44,73 @@ module JamRuby
|
|||
belongs_to :genre, class_name: "JamRuby::Genre"
|
||||
belongs_to :licensor , class_name: 'JamRuby::JamTrackLicensor', foreign_key: 'licensor_id'
|
||||
|
||||
has_many :jam_track_tracks, :class_name => "JamRuby::JamTrackTrack", order: 'position ASC'
|
||||
has_many :jam_track_tracks, :class_name => "JamRuby::JamTrackTrack", order: 'position ASC, part ASC, instrument_id ASC'
|
||||
has_many :jam_track_tap_ins, :class_name => "JamRuby::JamTrackTapIn", order: 'offset_time ASC'
|
||||
|
||||
has_many :jam_track_rights, :class_name => "JamRuby::JamTrackRight" #, inverse_of: 'jam_track', :foreign_key => "jam_track_id"
|
||||
has_many :jam_track_rights, :class_name => "JamRuby::JamTrackRight" #, inverse_of: 'jam_track', :foreign_key => "jam_track_id" # '
|
||||
|
||||
has_many :owners, :through => :jam_track_rights, :class_name => "JamRuby::User", :source => :user
|
||||
|
||||
has_many :playing_sessions, :class_name => "JamRuby::ActiveMusicSession"
|
||||
|
||||
has_many :recordings, :class_name => "JamRuby::Recording"
|
||||
|
||||
# VRFS-2916 jam_tracks.id is varchar: REMOVE
|
||||
# has_many :plays, :class_name => "JamRuby::PlayablePlay", :foreign_key => :jam_track_id, :dependent => :destroy
|
||||
# VRFS-2916 jam_tracks.id is varchar: ADD
|
||||
has_many :plays, :class_name => "JamRuby::PlayablePlay", :as => :playable, :dependent => :destroy
|
||||
|
||||
accepts_nested_attributes_for :jam_track_tracks, allow_destroy: true
|
||||
accepts_nested_attributes_for :jam_track_tap_ins, allow_destroy: true
|
||||
|
||||
def duplicate_positions?
|
||||
counter = {}
|
||||
jam_track_tracks.each do |track|
|
||||
count = counter[track.position]
|
||||
if count.nil?
|
||||
count = 0
|
||||
end
|
||||
puts "count #{count}"
|
||||
counter[track.position] = count + 1
|
||||
end
|
||||
|
||||
duplicate = false
|
||||
counter.each do|position, count|
|
||||
if count > 1
|
||||
duplicate = true
|
||||
break
|
||||
end
|
||||
end
|
||||
duplicate
|
||||
end
|
||||
|
||||
class << self
|
||||
# @return array[artist_name(string)]
|
||||
def all_artists
|
||||
JamTrack.select("original_artist").
|
||||
group("original_artist").
|
||||
collect{|jam_track|jam_track.original_artist}
|
||||
end
|
||||
|
||||
# @return array[JamTrack] for given artist_name
|
||||
def tracks_for_artist(artist_name)
|
||||
JamTrack.where("original_artist=?", artist_name).all
|
||||
end
|
||||
|
||||
def index(options, user)
|
||||
if options[:page]
|
||||
page = options[:page].to_i
|
||||
per_page = options[:per_page].to_i
|
||||
|
||||
if per_page == 0
|
||||
# try and see if limit was specified
|
||||
limit = options[:limit]
|
||||
limit ||= 20
|
||||
limit = limit.to_i
|
||||
else
|
||||
limit = per_page
|
||||
end
|
||||
|
||||
start = (page -1 )* per_page
|
||||
limit = per_page
|
||||
else
|
||||
|
|
@ -85,6 +133,14 @@ module JamRuby
|
|||
query = query.joins(:jam_track_rights)
|
||||
query = query.where("jam_track_rights.user_id = ?", user.id)
|
||||
end
|
||||
|
||||
if options[:artist].present?
|
||||
query = query.where("original_artist=?", options[:artist])
|
||||
end
|
||||
|
||||
if options[:group_artist]
|
||||
query = query.group("original_artist")
|
||||
end
|
||||
|
||||
query = query.where("jam_tracks.status = ?", 'Production') unless user.admin
|
||||
query = query.where("jam_tracks.genre_id = '#{options[:genre]}'") unless options[:genre].blank?
|
||||
|
|
@ -114,6 +170,6 @@ module JamRuby
|
|||
|
||||
def right_for_user(user)
|
||||
jam_track_rights.where("user_id=?", user).first
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ module JamRuby
|
|||
remove_url_44!
|
||||
end
|
||||
|
||||
|
||||
def enqueue(sample_rate=48)
|
||||
begin
|
||||
JamTrackRight.where(:id => self.id).update_all(:signing_queued_at => Time.now, :signing_started_at => nil, :last_signed_at => nil)
|
||||
|
|
@ -124,6 +125,7 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
# @return true if signed && file exists for the sample_rate specifed:
|
||||
def ready?(sample_rate=48)
|
||||
if sample_rate==48
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ module JamRuby
|
|||
validates :part, length: {maximum: 25}
|
||||
validates :track_type, inclusion: {in: TRACK_TYPE }
|
||||
validates :preview_start_time, numericality: {only_integer: true}, length: {in: 1..1000}, :allow_nil => true
|
||||
validates_uniqueness_of :position, scope: :jam_track_id
|
||||
validates_uniqueness_of :part, scope: [:jam_track_id, :instrument_id]
|
||||
# validates :jam_track, presence: true
|
||||
|
||||
|
|
|
|||
|
|
@ -136,23 +136,43 @@ module JamRuby
|
|||
def manifest
|
||||
one_day = 60 * 60 * 24
|
||||
|
||||
jam_track_offset = 0
|
||||
|
||||
if recording.timeline
|
||||
recording_timeline_data = JSON.parse(recording.timeline)
|
||||
|
||||
recording_start_time = recording_timeline_data["recording_start_time"]
|
||||
jam_track_play_start_time = recording_timeline_data["jam_track_play_start_time"]
|
||||
jam_track_recording_start_play_offset = recording_timeline_data["jam_track_recording_start_play_offset"]
|
||||
|
||||
jam_track_offset = -jam_track_recording_start_play_offset
|
||||
end
|
||||
|
||||
manifest = { "files" => [], "timeline" => [] }
|
||||
mix_params = []
|
||||
|
||||
|
||||
# this 'pick limiter' logic will ensure that we set a limiter on the 1st recorded_track we come across.
|
||||
pick_limiter = false
|
||||
if recording.is_jamtrack_recording?
|
||||
# we only use the limiter feature if this is a JamTrack recording
|
||||
# by setting this to true, the 1st recorded_track in the database will be the limiter
|
||||
pick_limiter = true
|
||||
end
|
||||
|
||||
recording.recorded_tracks.each do |recorded_track|
|
||||
manifest["files"] << { "filename" => recorded_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
# change to 1.0 level later
|
||||
manifest["files"] << { "filename" => recorded_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0, limiter:pick_limiter }
|
||||
pick_limiter = false
|
||||
mix_params << { "level" => 1.0, "balance" => 0 }
|
||||
end
|
||||
|
||||
recording.recorded_backing_tracks.each do |recorded_backing_track|
|
||||
manifest["files"] << { "filename" => recorded_backing_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
# change to 1.0 level later
|
||||
mix_params << { "level" => 1.0, "balance" => 0 }
|
||||
end
|
||||
|
||||
recording.recorded_jam_track_tracks.each do |recorded_jam_track_track|
|
||||
manifest["files"] << { "filename" => recorded_jam_track_track.jam_track_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 }
|
||||
manifest["files"] << { "filename" => recorded_jam_track_track.jam_track_track.sign_url(one_day), "codec" => "vorbis", "offset" => jam_track_offset }
|
||||
# let's look for level info from the client
|
||||
level = 1.0 # default value - means no effect
|
||||
if recorded_jam_track_track.timeline
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ module JamRuby
|
|||
filter_approved = only_approved ? 'AND rrrs.chosen = true' : ''
|
||||
|
||||
MusicSession.where(%Q{music_sessions.canceled = FALSE AND
|
||||
music_sessions.create_type != '#{CREATE_TYPE_QUICK_START}' AND
|
||||
(music_sessions.create_type is NULL OR music_sessions.create_type != '#{CREATE_TYPE_QUICK_START}') AND
|
||||
(music_sessions.scheduled_start is NULL OR music_sessions.scheduled_start > NOW() - '4 hour'::INTERVAL) AND
|
||||
music_sessions.id in (
|
||||
select distinct(rs.music_session_id)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,27 @@ module JamRuby
|
|||
class PlayablePlay < ActiveRecord::Base
|
||||
self.table_name = "playable_plays"
|
||||
|
||||
belongs_to :playable, :polymorphic => :true, :counter_cache => :play_count
|
||||
belongs_to :playable, :polymorphic => :true
|
||||
# VRFS-2916 jam_tracks.id is varchar: REMOVE
|
||||
#belongs_to :jam_track, :foreign_key => :jam_track_id
|
||||
belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "player_id"
|
||||
belongs_to :claimed_recording, :class_name => "JamRuby::ClaimedRecording", :foreign_key => "claimed_recording_id"
|
||||
|
||||
validate do
|
||||
# VRFS-2916 jam_tracks.id is varchar: REMOVE
|
||||
#if !playable_id && !jam_track_id
|
||||
# self.errors[:base] << 'No playable instance detected'
|
||||
#end
|
||||
|
||||
# VRFS-2916 jam_tracks.id is varchar: ADD
|
||||
if !playable_id
|
||||
self.errors[:base] << 'No playable instance detected'
|
||||
end
|
||||
|
||||
if !user
|
||||
self.errors[:base] << 'No user detected'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ module JamRuby
|
|||
validates :user, presence: true
|
||||
validates :jam_track_track, presence:true
|
||||
|
||||
def self.create_from_jam_track_track(jam_track_track, recording)
|
||||
def self.create_from_jam_track_track(jam_track_track, recording, user)
|
||||
recorded_jam_track_track = self.new
|
||||
recorded_jam_track_track.recording = recording
|
||||
recorded_jam_track_track.jam_track_track = jam_track_track
|
||||
recorded_jam_track_track.user = user
|
||||
recorded_jam_track_track.save
|
||||
recorded_jam_track_track
|
||||
end
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ module JamRuby
|
|||
self.comments.size
|
||||
end
|
||||
|
||||
def is_jamtrack_recording?
|
||||
!jam_track_id.nil?
|
||||
end
|
||||
|
||||
def high_quality_mix?
|
||||
has_final_mix
|
||||
end
|
||||
|
|
@ -229,11 +233,13 @@ module JamRuby
|
|||
|
||||
if music_session.jam_track
|
||||
music_session.jam_track.jam_track_tracks.each do |jam_track_track|
|
||||
recording.recorded_jam_track_tracks << RecordedJamTrackTrack.create_from_jam_track_track(jam_track_track, recording)
|
||||
recording.recorded_jam_track_tracks << RecordedJamTrackTrack.create_from_jam_track_track(jam_track_track, recording, owner) if jam_track_track.track_type == 'Track'
|
||||
end
|
||||
recording.jam_track = music_session.jam_track
|
||||
recording.jam_track_initiator = music_session.jam_track_initiator
|
||||
end
|
||||
|
||||
recording.save
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -690,19 +696,17 @@ module JamRuby
|
|||
end
|
||||
|
||||
def add_timeline(timeline)
|
||||
tracks = timeline["tracks"]
|
||||
global = timeline["global"]
|
||||
raise JamArgumentError, "global must be specified" unless global
|
||||
|
||||
tracks = timeline["tracks"]
|
||||
raise JamArgumentError, "tracks must be specified" unless tracks
|
||||
|
||||
Recording.where(id: self.id).update_all(timeline: global.to_json)
|
||||
|
||||
jam_tracks = tracks.select {|track| track["type"] == "jam_track"}
|
||||
jam_tracks.each do |client_jam_track|
|
||||
recorded_jam_track_track = RecordedJamTrackTrack.find_by_jam_track_track_id(client_jam_track["id"])
|
||||
if recorded_jam_track_track
|
||||
recorded_jam_track_track.timeline = client_jam_track["timeline"].to_json
|
||||
recorded_jam_track_track.save!
|
||||
else
|
||||
@@log.error("unable to find JamTrackTrack with id #{recorded_jam_track_track.id}")
|
||||
end
|
||||
RecordedJamTrackTrack.where(recording_id: id, jam_track_track_id: client_jam_track["id"]).update_all(timeline: client_jam_track["timeline"].to_json)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -8,27 +8,105 @@ module JamRuby
|
|||
validates :cart_id, presence: true
|
||||
validates :cart_type, presence: true
|
||||
validates :cart_class_name, presence: true
|
||||
validates :marked_for_redeem, numericality: {only_integer: true}
|
||||
|
||||
default_scope order('created_at DESC')
|
||||
|
||||
def product_info
|
||||
product = self.cart_product
|
||||
{name: product.name, price: product.price, product_id: cart_id} unless product.nil?
|
||||
{name: product.name, price: product.price, product_id: cart_id, plan_code: product.plan_code, total_price: total_price(product), quantity: quantity, marked_for_redeem: marked_for_redeem} unless product.nil?
|
||||
end
|
||||
|
||||
# multiply (quantity - redeemable) by price
|
||||
def total_price(product)
|
||||
(quantity - marked_for_redeem) * product.price
|
||||
end
|
||||
|
||||
def cart_product
|
||||
self.cart_class_name.classify.constantize.find_by_id self.cart_id unless self.cart_class_name.blank?
|
||||
self.cart_class_name.classify.constantize.find_by_id(self.cart_id) unless self.cart_class_name.blank?
|
||||
end
|
||||
|
||||
def self.create user, product, quantity = 1
|
||||
def redeem(mark_redeem)
|
||||
self.marked_for_redeem = mark_redeem ? 1 : 0
|
||||
end
|
||||
|
||||
def free?
|
||||
marked_for_redeem == quantity
|
||||
end
|
||||
|
||||
def self.create user, product, quantity = 1, mark_redeem = false
|
||||
cart = ShoppingCart.new
|
||||
cart.user = user
|
||||
if user.is_a?(User)
|
||||
cart.user = user
|
||||
else
|
||||
cart.anonymous_user_id = user.id
|
||||
end
|
||||
|
||||
cart.cart_type = product.class::PRODUCT_TYPE
|
||||
cart.cart_class_name = product.class.name
|
||||
cart.cart_id = product.id
|
||||
cart.quantity = quantity
|
||||
cart.redeem(mark_redeem)
|
||||
cart.save
|
||||
cart
|
||||
end
|
||||
|
||||
# if the user has a redeemable jam_track still on their account, then also check if any shopping carts have already been marked.
|
||||
# if no shpping carts have been marked, then mark it redeemable
|
||||
# should be wrapped in a TRANSACTION
|
||||
def self.user_has_redeemable_jam_track?(any_user)
|
||||
mark_redeem = false
|
||||
if APP_CONFIG.one_free_jamtrack_per_user && any_user.has_redeemable_jamtrack
|
||||
mark_redeem = true # start out assuming we can redeem...
|
||||
any_user.shopping_carts.each do |shopping_cart|
|
||||
# but if we find any shopping cart item already marked for redeem, then back out of mark_redeem=true
|
||||
if shopping_cart.cart_type == JamTrack::PRODUCT_TYPE && shopping_cart.marked_for_redeem > 0
|
||||
mark_redeem = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
mark_redeem
|
||||
end
|
||||
|
||||
# adds a jam_track to cart, checking for promotions
|
||||
def self.add_jam_track_to_cart(any_user, jam_track)
|
||||
cart = nil
|
||||
ShoppingCart.transaction do
|
||||
# does this user already have this JamTrack in their cart? If so, don't add it.
|
||||
|
||||
duplicate_found = false
|
||||
any_user.shopping_carts.each do |shopping_cart|
|
||||
if shopping_cart.cart_type == JamTrack::PRODUCT_TYPE && shopping_cart.cart_id == jam_track.id
|
||||
duplicate_found = true
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
unless duplicate_found
|
||||
mark_redeem = ShoppingCart.user_has_redeemable_jam_track?(any_user)
|
||||
cart = ShoppingCart.create(any_user, jam_track, 1, mark_redeem)
|
||||
end
|
||||
end
|
||||
cart
|
||||
end
|
||||
|
||||
# deletes a jam track from the shopping cart, updating redeem flag as necessary
|
||||
def self.remove_jam_track_from_cart(any_user, cart)
|
||||
ShoppingCart.transaction do
|
||||
cart.destroy
|
||||
# check if we should move the redemption
|
||||
mark_redeem = ShoppingCart.user_has_redeemable_jam_track?(any_user)
|
||||
|
||||
carts = any_user.shopping_carts
|
||||
|
||||
# if we find any carts on the account, mark one redeemable
|
||||
if mark_redeem && carts.length > 0
|
||||
carts[0].redeem(mark_redeem)
|
||||
carts[0].save
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -71,6 +71,11 @@ module JamRuby
|
|||
has_many :playing_claimed_recordings, :class_name => "JamRuby::ActiveMusicSession", :inverse_of => :claimed_recording_initiator
|
||||
has_many :playing_jam_tracks, :class_name => "JamRuby::ActiveMusicSession", :inverse_of => :jam_track_initiator
|
||||
|
||||
# VRFS-2916 jam_tracks.id is varchar: REMOVE
|
||||
# has_many :jam_tracks_played, :class_name => "JamRuby::PlayablePlay", :foreign_key => 'player_id', :conditions => "jam_track_id IS NOT NULL"
|
||||
# VRFS-2916 jam_tracks.id is varchar: ADD
|
||||
has_many :jam_tracks_played, :class_name => "JamRuby::PlayablePlay", :foreign_key => 'player_id', :conditions => ["playable_type = 'JamRuby::JamTrack'"]
|
||||
|
||||
# self.id = user_id in likes table
|
||||
has_many :likings, :class_name => "JamRuby::Like", :inverse_of => :user, :dependent => :destroy
|
||||
|
||||
|
|
@ -176,6 +181,8 @@ module JamRuby
|
|||
validates_confirmation_of :password, :if => :should_validate_password?
|
||||
|
||||
validates :terms_of_service, :acceptance => {:accept => true, :on => :create, :allow_nil => false }
|
||||
validates :reuse_card, :inclusion => {:in => [true, false]}
|
||||
validates :has_redeemable_jamtrack, :inclusion => {:in => [true, false]}
|
||||
validates :subscribe_email, :inclusion => {:in => [nil, true, false]}
|
||||
validates :musician, :inclusion => {:in => [true, false]}
|
||||
validates :show_whats_next, :inclusion => {:in => [nil, true, false]}
|
||||
|
|
@ -366,6 +373,10 @@ module JamRuby
|
|||
MusicSession.scheduled_rsvp(self, true).length
|
||||
end
|
||||
|
||||
def purchased_jamtracks_count
|
||||
self.purchased_jam_tracks.count
|
||||
end
|
||||
|
||||
def joined_score
|
||||
return nil unless has_attribute?(:score)
|
||||
a = read_attribute(:score)
|
||||
|
|
@ -961,6 +972,8 @@ module JamRuby
|
|||
signup_confirm_url = options[:signup_confirm_url]
|
||||
affiliate_referral_id = options[:affiliate_referral_id]
|
||||
recaptcha_failed = options[:recaptcha_failed]
|
||||
any_user = options[:any_user]
|
||||
reuse_card = options[:reuse_card]
|
||||
|
||||
user = User.new
|
||||
|
||||
|
|
@ -971,6 +984,7 @@ module JamRuby
|
|||
user.subscribe_email = true
|
||||
user.terms_of_service = terms_of_service
|
||||
user.musician = musician
|
||||
user.reuse_card unless reuse_card.nil?
|
||||
|
||||
# FIXME: Setting random password for social network logins. This
|
||||
# is because we have validations all over the place on this.
|
||||
|
|
@ -1015,6 +1029,9 @@ module JamRuby
|
|||
|
||||
user.photo_url = photo_url
|
||||
|
||||
# copy over the shopping cart to the new user, if a shopping cart is provided
|
||||
user.shopping_carts = any_user.shopping_carts if any_user
|
||||
|
||||
unless fb_signup.nil?
|
||||
user.update_fb_authorization(fb_signup)
|
||||
|
||||
|
|
@ -1536,6 +1553,11 @@ module JamRuby
|
|||
stats['audio_latency_avg'] = result['last_jam_audio_latency_avg'].to_f
|
||||
stats
|
||||
end
|
||||
|
||||
def destroy_all_shopping_carts
|
||||
ShoppingCart.where("user_id=?", self).destroy_all
|
||||
end
|
||||
|
||||
private
|
||||
def create_remember_token
|
||||
self.remember_token = SecureRandom.urlsafe_base64
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ module JamRuby
|
|||
def initialize()
|
||||
end
|
||||
|
||||
def create_account(current_user, billing_info=nil)
|
||||
def create_account(current_user, billing_info)
|
||||
options = account_hash(current_user, billing_info)
|
||||
account = nil
|
||||
begin
|
||||
|
|
@ -12,7 +12,7 @@ module JamRuby
|
|||
account = Recurly::Account.create(options)
|
||||
raise RecurlyClientError.new(account.errors) if account.errors.any?
|
||||
rescue Recurly::Error, NoMethodError => x
|
||||
puts "Error: #{x} : #{Kernel.caller}"
|
||||
#puts "Error: #{x} : #{Kernel.caller}"
|
||||
raise RecurlyClientError, x.to_s
|
||||
else
|
||||
if account
|
||||
|
|
@ -37,7 +37,9 @@ module JamRuby
|
|||
end
|
||||
|
||||
def get_account(current_user)
|
||||
(current_user && current_user.recurly_code) ? Recurly::Account.find(current_user.recurly_code) : nil
|
||||
current_user && current_user.recurly_code ? Recurly::Account.find(current_user.recurly_code) : nil
|
||||
rescue Recurly::Error => x
|
||||
raise RecurlyClientError, x.to_s
|
||||
end
|
||||
|
||||
def update_account(current_user, billing_info=nil)
|
||||
|
|
@ -53,12 +55,35 @@ module JamRuby
|
|||
account
|
||||
end
|
||||
|
||||
def payment_history(current_user)
|
||||
payments = []
|
||||
account = get_account(current_user)
|
||||
if(account.present?)
|
||||
begin
|
||||
account.transactions.find_each do |transaction|
|
||||
if transaction.amount_in_cents > 0 # Account creation adds a transaction record
|
||||
payments << {
|
||||
:created_at => transaction.created_at,
|
||||
:amount_in_cents => transaction.amount_in_cents,
|
||||
:status => transaction.status,
|
||||
:payment_method => transaction.payment_method,
|
||||
:reference => transaction.reference
|
||||
}
|
||||
end
|
||||
end
|
||||
rescue Recurly::Error, NoMethodError => x
|
||||
raise RecurlyClientError, x.to_s
|
||||
end
|
||||
end
|
||||
payments
|
||||
end
|
||||
|
||||
def update_billing_info(current_user, billing_info=nil)
|
||||
account = get_account(current_user)
|
||||
if (account.present?)
|
||||
begin
|
||||
account.billing_info=billing_info
|
||||
account.billing_info.save
|
||||
account.billing_info = billing_info
|
||||
account.billing_info.save
|
||||
rescue Recurly::Error, NoMethodError => x
|
||||
raise RecurlyClientError, x.to_s
|
||||
end
|
||||
|
|
@ -145,7 +170,7 @@ module JamRuby
|
|||
raise RecurlyClientError.new(plan.errors) if plan.errors.any?
|
||||
end
|
||||
|
||||
def place_order(current_user, jam_track)
|
||||
def place_order(current_user, jam_track, shopping_cart)
|
||||
jam_track_right = nil
|
||||
account = get_account(current_user)
|
||||
if (account.present?)
|
||||
|
|
@ -160,13 +185,22 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
free = false
|
||||
|
||||
# this means we already have a subscription, so don't try to create a new one for the same plan (Recurly would fail this anyway)
|
||||
unless recurly_subscription_uuid
|
||||
|
||||
subscription = Recurly::Subscription.create(:account=>account, :plan_code=>jam_track.plan_code)
|
||||
# if the shopping cart was specified, see if the item should be free
|
||||
free = shopping_cart.nil? ? false : shopping_cart.free?
|
||||
# and if it's free, squish the charge to 0.
|
||||
unit_amount_in_cents = free ? 0 : nil
|
||||
subscription = Recurly::Subscription.create(:account=>account, :plan_code=>jam_track.plan_code, unit_amount_in_cents: unit_amount_in_cents)
|
||||
|
||||
raise RecurlyClientError.new(subscription.errors) if subscription.errors.any?
|
||||
|
||||
# delete from shopping cart the subscription
|
||||
shopping_cart.destroy if shopping_cart
|
||||
|
||||
# Reload and make sure it went through:
|
||||
account = get_account(current_user)
|
||||
|
||||
|
|
@ -180,11 +214,19 @@ module JamRuby
|
|||
|
||||
raise RecurlyClientError, "Plan code '#{paid_subscription.plan_code}' doesn't match jam track: '#{jam_track.plan_code}'" unless recurly_subscription_uuid
|
||||
|
||||
jam_track_right=JamRuby::JamTrackRight.find_or_create_by_user_id_and_jam_track_id(current_user.id, jam_track.id)
|
||||
jam_track_right = JamRuby::JamTrackRight.find_or_create_by_user_id_and_jam_track_id(current_user.id, jam_track.id) do |jam_track_right|
|
||||
jam_track_right.redeemed = free
|
||||
end
|
||||
|
||||
User.where(id: current_user.id).update_all(has_redeemable_jamtrack: false) if free
|
||||
|
||||
# also if the purchase was a free one, then update the user record to no longer allow redeemed jamtracks
|
||||
# this can't go in the block above, as it's here to fix bad subscription UUIDs in an update path
|
||||
if jam_track_right.recurly_subscription_uuid != recurly_subscription_uuid
|
||||
jam_track_right.recurly_subscription_uuid = recurly_subscription_uuid
|
||||
jam_track_right.save
|
||||
end
|
||||
|
||||
raise RecurlyClientError.new("Error creating jam_track_right for jam_track: #{jam_track.id}") if jam_track_right.nil?
|
||||
raise RecurlyClientError.new(jam_track_right.errors) if jam_track_right.errors.any?
|
||||
rescue Recurly::Error, NoMethodError => x
|
||||
|
|
@ -198,7 +240,7 @@ module JamRuby
|
|||
jam_track_right
|
||||
end
|
||||
|
||||
def find_or_create_account(current_user, billing_info=nil)
|
||||
def find_or_create_account(current_user, billing_info)
|
||||
account = get_account(current_user)
|
||||
|
||||
if(account.nil?)
|
||||
|
|
|
|||
|
|
@ -260,6 +260,10 @@ module JamRuby
|
|||
end
|
||||
|
||||
@manifest = symbolize_keys(mix.manifest)
|
||||
@@log.debug("manifest")
|
||||
@@log.debug("--------")
|
||||
@@log.debug(JSON.pretty_generate(@manifest))
|
||||
|
||||
@manifest[:mix_id] = mix_id # slip in the mix_id so that the job can add it to the ogg comments
|
||||
|
||||
# sanity check the manifest
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ FactoryGirl.define do
|
|||
musician true
|
||||
terms_of_service true
|
||||
last_jam_audio_latency 5
|
||||
reuse_card true
|
||||
|
||||
#u.association :musician_instrument, factory: :musician_instrument, user: u
|
||||
|
||||
|
|
@ -583,6 +584,7 @@ FactoryGirl.define do
|
|||
end
|
||||
|
||||
factory :playable_play, :class => JamRuby::PlayablePlay do
|
||||
association :user, factory: :user
|
||||
end
|
||||
|
||||
factory :recording_like, :class => JamRuby::RecordingLiker do
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ describe JamTrackRight do
|
|||
s3.upload(jam_track_track.manually_uploaded_filename(:url_48), ogg_path)
|
||||
jam_track_track[:url_48] = jam_track_track.manually_uploaded_filename(:url_48)
|
||||
jam_track_track.save!
|
||||
|
||||
jam_track_track[:url_48].should == jam_track_track.manually_uploaded_filename(:url_48)
|
||||
|
||||
# verify it's on S3
|
||||
|
|
@ -97,7 +98,7 @@ describe JamTrackRight do
|
|||
end
|
||||
|
||||
it "bogus key" do
|
||||
JamTrackRight.list_keys(user, [2112]).should eq([])
|
||||
JamTrackRight.list_keys(user, ['2112']).should eq([])
|
||||
end
|
||||
|
||||
it "valid track with no rights to it by querying user" do
|
||||
|
|
|
|||
|
|
@ -14,6 +14,30 @@ describe JamTrack do
|
|||
jam_track.licensor.jam_tracks.should == [jam_track]
|
||||
end
|
||||
|
||||
describe 'plays' do
|
||||
it "creates played instance properly" do
|
||||
@jam_track = FactoryGirl.create(:jam_track)
|
||||
play = PlayablePlay.new
|
||||
|
||||
# VRFS-2916 jam_tracks.id is varchar: REMOVE
|
||||
# play.jam_track = @jam_track
|
||||
# VRFS-2916 jam_tracks.id is varchar: ADD
|
||||
play.playable = @jam_track
|
||||
|
||||
play.user = user
|
||||
play.save!
|
||||
expect(@jam_track.plays.count).to eq(1)
|
||||
expect(@jam_track.plays[0].user.id).to eq(user.id)
|
||||
expect(user.jam_tracks_played.count).to eq(1)
|
||||
end
|
||||
it "handles played errors" do
|
||||
play = PlayablePlay.new
|
||||
play.user = user
|
||||
play.save
|
||||
expect(play.errors.count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe "index" do
|
||||
it "empty query" do
|
||||
query, pager = JamTrack.index({}, user)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ describe JamTrackTrack do
|
|||
jam_track_track_1 = FactoryGirl.create(:jam_track_track, position: 1, jam_track: jam_track)
|
||||
jam_track_track_2 = FactoryGirl.build(:jam_track_track, position: 1, jam_track: jam_track)
|
||||
jam_track_track_2.valid?.should == false
|
||||
jam_track_track_2.errors[:position].should == ['has already been taken']
|
||||
#jam_track_track_2.errors[:position].should == ['has already been taken']
|
||||
end
|
||||
|
||||
it "jam_track required" do
|
||||
|
|
|
|||
|
|
@ -854,6 +854,13 @@ describe MusicSession do
|
|||
music_session_1.rsvp_slots[0].rsvp_requests_rsvp_slots[0].save!
|
||||
MusicSession.scheduled_rsvp(creator_1, true).should == []
|
||||
end
|
||||
|
||||
it "create_type = nil will still return RSVPs" do
|
||||
music_session_1.create_type = nil
|
||||
music_session_1.save!
|
||||
|
||||
MusicSession.scheduled_rsvp(creator_1, true).should == [music_session_1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1080,6 +1080,7 @@ describe Recording do
|
|||
let(:recording) {recorded_jam_track_track.recording}
|
||||
let(:timeline_data) {{"sample" => "data"}}
|
||||
let(:good_timeline) { {
|
||||
"global" => {"recording_start_time" => 0, "jam_track_play_start_time" => 0, "jam_track_recording_start_play_offset" => 0},
|
||||
"tracks" => [
|
||||
{
|
||||
"id" => recorded_jam_track_track.jam_track_track.id,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ describe ShoppingCart do
|
|||
|
||||
let(:user) { FactoryGirl.create(:user) }
|
||||
let(:jam_track) {FactoryGirl.create(:jam_track) }
|
||||
let(:jam_track2) {FactoryGirl.create(:jam_track) }
|
||||
|
||||
before(:each) do
|
||||
ShoppingCart.delete_all
|
||||
|
|
@ -20,4 +21,48 @@ describe ShoppingCart do
|
|||
user.shopping_carts[0].quantity.should == 1
|
||||
end
|
||||
|
||||
it "should not add duplicate JamTrack to ShoppingCart" do
|
||||
cart1 = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
cart1.should_not be_nil
|
||||
user.reload
|
||||
cart2 = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
cart2.should be_nil
|
||||
|
||||
end
|
||||
|
||||
describe "redeemable behavior" do
|
||||
it "adds redeemable item to shopping cart" do
|
||||
|
||||
user.has_redeemable_jamtrack.should be_true
|
||||
|
||||
# first item added to shopping cart should be marked for redemption
|
||||
cart = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
cart.marked_for_redeem.should eq(1)
|
||||
|
||||
# but the second item should not
|
||||
|
||||
user.reload
|
||||
|
||||
cart = ShoppingCart.add_jam_track_to_cart(user, jam_track2)
|
||||
cart.marked_for_redeem.should eq(0)
|
||||
end
|
||||
|
||||
it "removes redeemable item to shopping cart" do
|
||||
|
||||
user.has_redeemable_jamtrack.should be_true
|
||||
cart1 = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
cart1.should_not be_nil
|
||||
user.reload
|
||||
cart2 = ShoppingCart.add_jam_track_to_cart(user, jam_track2)
|
||||
cart2.should_not be_nil
|
||||
|
||||
cart1.marked_for_redeem.should eq(1)
|
||||
cart2.marked_for_redeem.should eq(0)
|
||||
ShoppingCart.remove_jam_track_from_cart(user, jam_track)
|
||||
|
||||
user.shopping_carts.length.should eq(1)
|
||||
cart2.reload
|
||||
cart1.marked_for_redeem.should eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -88,21 +88,23 @@ describe RecurlyClient do
|
|||
end
|
||||
|
||||
it "can place order" do
|
||||
history_items = @client.payment_history(@user).length
|
||||
@client.find_or_create_account(@user, @billing_info)
|
||||
expect{@client.place_order(@user, @jamtrack)}.not_to raise_error()
|
||||
expect{@client.place_order(@user, @jamtrack, nil)}.not_to raise_error()
|
||||
subs = @client.get_account(@user).subscriptions
|
||||
subs.should_not be_nil
|
||||
subs.should have(1).items
|
||||
@user.jam_track_rights.should_not be_nil
|
||||
@user.jam_track_rights.should have(1).items
|
||||
@user.jam_track_rights.last.jam_track.id.should eq(@jamtrack.id)
|
||||
@client.payment_history(@user).should have(history_items+1).items
|
||||
end
|
||||
|
||||
it "can refund subscription" do
|
||||
@client.find_or_create_account(@user, @billing_info)
|
||||
|
||||
# Place order:
|
||||
expect{@client.place_order(@user, @jamtrack)}.not_to raise_error()
|
||||
expect{@client.place_order(@user, @jamtrack, nil)}.not_to raise_error()
|
||||
active_subs=@client.get_account(@user).subscriptions.find_all{|t|t.state=='active'}
|
||||
@jamtrack.reload
|
||||
@jamtrack.jam_track_rights.should have(1).items
|
||||
|
|
@ -118,10 +120,10 @@ describe RecurlyClient do
|
|||
|
||||
it "detects error on double order" do
|
||||
@client.find_or_create_account(@user, @billing_info)
|
||||
jam_track_right = @client.place_order(@user, @jamtrack)
|
||||
jam_track_right = @client.place_order(@user, @jamtrack, nil)
|
||||
jam_track_right.recurly_subscription_uuid.should_not be_nil
|
||||
|
||||
jam_track_right2 = @client.place_order(@user, @jamtrack)
|
||||
jam_track_right2 = @client.place_order(@user, @jamtrack, nil)
|
||||
jam_track_right.should eq(jam_track_right2)
|
||||
jam_track_right.recurly_subscription_uuid.should eq(jam_track_right.recurly_subscription_uuid)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ describe JamTracksBuilder do
|
|||
jam_track_track.save!
|
||||
|
||||
jam_track_track[:url_48].should == jam_track_track.manually_uploaded_filename(:url_48)
|
||||
|
||||
|
||||
# verify it's on S3
|
||||
@s3.exists?(jam_track_track[:url_48]).should be_true
|
||||
@s3.length(jam_track_track[:url_48]).should == File.size?(ogg_path)
|
||||
|
|
|
|||
|
|
@ -166,6 +166,10 @@ def app_config
|
|||
20 # 20 seconds
|
||||
end
|
||||
|
||||
def one_free_jamtrack_per_user
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ gem 'aasm', '3.0.16'
|
|||
gem 'carrierwave', '0.9.0'
|
||||
gem 'carrierwave_direct'
|
||||
gem 'fog'
|
||||
gem 'jquery-payment-rails'
|
||||
gem 'haml-rails'
|
||||
gem 'unf' #optional fog dependency
|
||||
gem 'devise', '3.3.0' #3.4.0 causes uninitialized constant ActionController::Metal (NameError)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
Jasmine Javascript Unit Tests
|
||||
=============================
|
||||
|
||||
Open browser to localhost:3000/teaspoon
|
||||
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -33,6 +33,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
function licenseDetail(userDetail) {
|
||||
return (userDetail.purchased_jamtracks_count==0) ? "You don't currently own any JamTracks" : 'You currently own a license to use ' + userDetail.purchased_jamtracks_count + " JamTracks"
|
||||
}
|
||||
|
||||
function populateAccount(userDetail) {
|
||||
|
||||
var validProfiles = prettyPrintAudioProfiles(context.JK.getGoodConfigMap());
|
||||
|
|
@ -42,8 +46,10 @@
|
|||
var $template = $(context._.template($('#template-account-main').html(), {
|
||||
email: userDetail.email,
|
||||
name: userDetail.name,
|
||||
licenseDetail: licenseDetail(userDetail),
|
||||
location : userDetail.location,
|
||||
session : sessionSummary,
|
||||
paymentMethod: "mastercard",
|
||||
instruments : prettyPrintInstruments(userDetail.instruments),
|
||||
photoUrl : context.JK.resolveAvatarUrl(userDetail.photo_url),
|
||||
validProfiles : validProfiles,
|
||||
|
|
@ -94,20 +100,28 @@
|
|||
|
||||
// events for main screen
|
||||
function events() {
|
||||
// wire up main panel clicks
|
||||
// wire up main panel clicks:
|
||||
$('#account-content-scroller').on('click', '#account-scheduled-sessions-link', function(evt) { evt.stopPropagation(); navToScheduledSessions(); return false; } );
|
||||
$('#account-content-scroller').on('click', '#account-my-jamtracks-link', function(evt) { evt.stopPropagation(); navToMyJamTracks(); return false; } );
|
||||
|
||||
$('#account-content-scroller').on('click', '#account-edit-identity-link', function(evt) { evt.stopPropagation(); navToEditIdentity(); return false; } );
|
||||
$('#account-content-scroller').on('click', '#account-edit-profile-link', function(evt) { evt.stopPropagation(); navToEditProfile(); return false; } );
|
||||
$('#account-content-scroller').on('click', '#account-edit-subscriptions-link', function(evt) { evt.stopPropagation(); navToEditSubscriptions(); return false; } );
|
||||
$('#account-content-scroller').on('click', '#account-edit-payments-link', function(evt) { evt.stopPropagation(); navToEditPayments(); return false; } );
|
||||
$('#account-content-scroller').on('click', '#account-edit-audio-link', function(evt) { evt.stopPropagation(); navToEditAudio(); return false; } );
|
||||
$('#account-content-scroller').on('avatar_changed', '#profile-avatar', function(evt, newAvatarUrl) { evt.stopPropagation(); updateAvatar(newAvatarUrl); return false; })
|
||||
|
||||
// License dialog:
|
||||
$("#account-content-scroller").on('click', '#account-view-license-link', function(evt) {evt.stopPropagation(); app.layout.showDialog('jamtrack-license-dialog'); return false; } );
|
||||
$("#account-content-scroller").on('click', '#account-payment-history-link', function(evt) {evt.stopPropagation(); app.layout.showDialog('jamtrack-payment-history-dialog'); return false; } );
|
||||
}
|
||||
|
||||
function renderAccount() {
|
||||
app.user().done(function() {
|
||||
rest.getUserDetail()
|
||||
.done(populateAccount)
|
||||
.error(app.ajaxError)
|
||||
.done(populateAccount)
|
||||
.error(app.ajaxError)
|
||||
})
|
||||
}
|
||||
|
||||
function navToScheduledSessions() {
|
||||
|
|
@ -115,6 +129,11 @@
|
|||
window.location = '/client#/account/sessions'
|
||||
}
|
||||
|
||||
function navToMyJamTracks() {
|
||||
resetForm();
|
||||
window.location = '/client#/account/jamtracks'
|
||||
}
|
||||
|
||||
function navToEditIdentity() {
|
||||
resetForm()
|
||||
window.location = '/client#/account/identity'
|
||||
|
|
@ -126,7 +145,7 @@
|
|||
}
|
||||
|
||||
function navToEditSubscriptions() {
|
||||
|
||||
window.location = '/client#/account/profile'
|
||||
}
|
||||
|
||||
function navToEditPayments() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {}
|
||||
|
||||
context.JK.AccountJamTracks = class AccountJamTracks
|
||||
constructor: (@app) ->
|
||||
@rest = context.JK.Rest()
|
||||
@client = context.jamClient
|
||||
@logger = context.JK.logger
|
||||
@screen = null
|
||||
@userId = context.JK.currentUserId;
|
||||
|
||||
initialize:() =>
|
||||
screenBindings =
|
||||
'beforeShow': @beforeShow
|
||||
'afterShow': @afterShow
|
||||
@app.bindScreen('account/jamtracks', screenBindings)
|
||||
@screen = $('#account-jamtracks')
|
||||
|
||||
beforeShow:() =>
|
||||
@logger.debug("beforeShow")
|
||||
rest.getPurchasedJamTracks({})
|
||||
.done(@populateJamTracks)
|
||||
.fail(@app.ajaxError);
|
||||
|
||||
afterShow:() =>
|
||||
@logger.debug("afterShow")
|
||||
|
||||
populateJamTracks:(data) =>
|
||||
@logger.debug("populateJamTracks", data)
|
||||
template = context._.template($('#template-account-jamtrack').html(), {jamtracks:data.jamtracks}, { variable: 'data' })
|
||||
|
||||
# template = context._.template($('#template-account-jamtrack').html(), {
|
||||
# jamtracks: data.jamtracks
|
||||
# current_user: @userId
|
||||
# }, variable: 'data')
|
||||
@logger.debug("TEMPLATE", template)
|
||||
this.appendJamTracks template
|
||||
@screen.find('.jamtrack-solo-session').on 'click', @soloSession
|
||||
@screen.find('.jamtrack-group-session').on 'click', @groupSession
|
||||
|
||||
appendJamTracks:(template) =>
|
||||
$('#account-my-jamtracks table tbody').replaceWith template
|
||||
|
||||
soloSession:(e) =>
|
||||
#context.location="client#/createSession"
|
||||
@logger.debug "BLEH", e
|
||||
jamRow = $(e.target).parents("tr")
|
||||
@logger.debug "BLEH2", e, jamRow.data()
|
||||
@createSession(jamRow.data(), true)
|
||||
#@logger.debug "BLEH", $(this), $(this).data()
|
||||
|
||||
groupSession:(e) =>
|
||||
#context.location="client#/createSession"
|
||||
jamRow = $(e.target).parents("tr")
|
||||
@createSession(jamRow.data(), false)
|
||||
|
||||
createSession:(sessionData, solo) =>
|
||||
tracks = context.JK.TrackHelpers.getUserTracks(context.jamClient)
|
||||
|
||||
if (context.JK.guardAgainstBrowser(@app))
|
||||
@logger.debug("CRATING SESSION", sessionData.genre, solo)
|
||||
data = {}
|
||||
data.client_id = @app.clientId
|
||||
#data.description = $('#description').val()
|
||||
data.description = "Jam Track Session"
|
||||
data.as_musician = true
|
||||
data.legal_terms = true
|
||||
data.intellectual_property = true
|
||||
data.approval_required = false
|
||||
data.musician_access = !solo
|
||||
data.fan_access = false
|
||||
data.fan_chat = false
|
||||
data.genre = [sessionData.genre]
|
||||
data.genres = [sessionData.genre]
|
||||
# data.genres = context.JK.GenreSelectorHelper.getSelectedGenres('#create-session-genre')
|
||||
# data.musician_access = if $('#musician-access option:selected').val() == 'true' then true else false
|
||||
# data.approval_required = if $('input[name=\'musician-access-option\']:checked').val() == 'true' then true else false
|
||||
# data.fan_access = if $('#fan-access option:selected').val() == 'true' then true else false
|
||||
# data.fan_chat = if $('input[name=\'fan-chat-option\']:checked').val() == 'true' then true else false
|
||||
# if $('#band-list option:selected').val() != ''
|
||||
# data.band = $('#band-list option:selected').val()
|
||||
data.audio_latency = context.jamClient.FTUEGetExpectedLatency().latency
|
||||
data.tracks = tracks
|
||||
|
||||
rest.legacyCreateSession(data).done((response) =>
|
||||
newSessionId = response.id
|
||||
context.location = '/client#/session/' + newSessionId
|
||||
# Re-loading the session settings will cause the form to reset with the right stuff in it.
|
||||
# This is an extra xhr call, but it keeps things to a single codepath
|
||||
loadSessionSettings()
|
||||
context.JK.GA.trackSessionCount data.musician_access, data.fan_access, invitationCount
|
||||
context.JK.GA.trackSessionMusicians context.JK.GA.SessionCreationTypes.create
|
||||
).fail (jqXHR) =>
|
||||
handled = false
|
||||
if jqXHR.status = 422
|
||||
response = JSON.parse(jqXHR.responseText)
|
||||
if response['errors'] and response['errors']['tracks'] and response['errors']['tracks'][0] == 'Please select at least one track'
|
||||
@app.notifyAlert 'No Inputs Configured', $('<span>You will need to reconfigure your audio device.</span>')
|
||||
handled = true
|
||||
if !handled
|
||||
@app.notifyServerError jqXHR, 'Unable to Create Session'
|
||||
|
||||
|
|
@ -168,13 +168,32 @@
|
|||
});
|
||||
|
||||
$btnSubmit.click(function(evt) {
|
||||
$document.triggerHandler(EVENTS.USER_UPDATED, response);
|
||||
|
||||
handleUpdateProfile();
|
||||
if (validate()) {
|
||||
handleUpdateProfile();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function validate() {
|
||||
// website
|
||||
if ($.trim($website.val()).length > 0) {
|
||||
|
||||
}
|
||||
|
||||
// SoundCloud
|
||||
if ($.trim($soundCloudUsername.val()).length > 0) {
|
||||
|
||||
}
|
||||
|
||||
// ReverbNation
|
||||
if ($.trim($reverbNationUsername.val())) {
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function navigateTo(targetLocation) {
|
||||
context.location = targetLocation;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
//= require jquery.browser
|
||||
//= require jquery.custom-protocol
|
||||
//= require jquery.exists
|
||||
//= require jquery.payment
|
||||
//= require jstz
|
||||
//= require class
|
||||
//= require AAC_underscore
|
||||
|
|
|
|||
|
|
@ -0,0 +1,385 @@
|
|||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.CheckoutOrderScreen = function (app) {
|
||||
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var jamTrackUtils = context.JK.JamTrackUtils;
|
||||
|
||||
var $screen = null;
|
||||
var $navigation = null;
|
||||
var $templateOrderContent = null;
|
||||
var $templatePurchasedJamTrack = null;
|
||||
var $orderPanel = null;
|
||||
var $thanksPanel = null;
|
||||
var $jamTrackInBrowser = null;
|
||||
var $purchasedJamTrack = null;
|
||||
var $purchasedJamTrackHeader = null;
|
||||
var $purchasedJamTracks = null;
|
||||
var $orderContent = null;
|
||||
var userDetail = null;
|
||||
var step = null;
|
||||
var downloadJamTracks = [];
|
||||
var purchasedJamTracks = null;
|
||||
var purchasedJamTrackIterator = 0;
|
||||
var $backBtn = null;
|
||||
var $orderPrompt = null;
|
||||
var $emptyCartPrompt = null;
|
||||
var $noAccountInfoPrompt = null;
|
||||
|
||||
|
||||
function beforeShow() {
|
||||
beforeShowOrder();
|
||||
}
|
||||
|
||||
|
||||
function afterShow(data) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
function beforeHide() {
|
||||
if(downloadJamTracks) {
|
||||
context._.each(downloadJamTracks, function(downloadJamTrack) {
|
||||
downloadJamTrack.destroy();
|
||||
downloadJamTrack.root.remove();
|
||||
})
|
||||
|
||||
downloadJamTracks = [];
|
||||
}
|
||||
purchasedJamTracks = null;
|
||||
purchasedJamTrackIterator = 0;
|
||||
}
|
||||
|
||||
function beforeShowOrder() {
|
||||
$orderPrompt.addClass('hidden')
|
||||
$emptyCartPrompt.addClass('hidden')
|
||||
$noAccountInfoPrompt.addClass('hidden')
|
||||
$orderPanel.removeClass("hidden")
|
||||
$thanksPanel.addClass("hidden")
|
||||
$screen.find(".place-order").addClass('disabled').off('click', placeOrder)
|
||||
$("#order_error").text('').addClass("hidden")
|
||||
step = 3;
|
||||
renderNavigation();
|
||||
populateOrderPage();
|
||||
}
|
||||
|
||||
|
||||
function populateOrderPage() {
|
||||
clearOrderPage();
|
||||
|
||||
rest.getShoppingCarts()
|
||||
.done(function(carts) {
|
||||
rest.getBillingInfo()
|
||||
.done(function(billingInfo) {
|
||||
renderOrderPage(carts, billingInfo)
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 404) {
|
||||
// no account for this user
|
||||
$noAccountInfoPrompt.removeClass('hidden')
|
||||
app.notify({ title: "No account information",
|
||||
text: "Please restart the checkout process." },
|
||||
null,
|
||||
true);
|
||||
}
|
||||
})
|
||||
})
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
|
||||
function renderOrderPage(carts, recurlyAccountInfo) {
|
||||
logger.debug("rendering order page")
|
||||
var data = {}
|
||||
|
||||
var sub_total = 0.0
|
||||
var taxes = 0.0
|
||||
$.each(carts, function(index, cart) {
|
||||
sub_total += parseFloat(cart.product_info.total_price)
|
||||
});
|
||||
if(carts.length == 0) {
|
||||
data.grand_total = '-.--'
|
||||
data.sub_total = '-.--'
|
||||
data.taxes = '-.--'
|
||||
data.shipping_handling = '-.--'
|
||||
}
|
||||
else {
|
||||
data.grand_total = 'Calculating...'
|
||||
data.sub_total = '$' + sub_total.toFixed(2)
|
||||
data.taxes = 'Calculating...'
|
||||
data.shipping_handling = '$0.00'
|
||||
}
|
||||
|
||||
data.carts = carts
|
||||
data.billing_info = recurlyAccountInfo.billing_info
|
||||
data.shipping_info = recurlyAccountInfo.address
|
||||
|
||||
data.shipping_as_billing = true; //jamTrackUtils.compareAddress(data.billing_info, data.shipping_info);
|
||||
|
||||
var orderContentHtml = $(
|
||||
context._.template(
|
||||
$templateOrderContent.html(),
|
||||
data,
|
||||
{variable: 'data'}
|
||||
)
|
||||
)
|
||||
|
||||
$orderContent.append(orderContentHtml)
|
||||
$orderPanel.find(".change-payment-info").on('click', moveToPaymentInfo)
|
||||
|
||||
var $placeOrder = $screen.find(".place-order")
|
||||
if(carts.length == 0) {
|
||||
$orderPrompt.addClass('hidden')
|
||||
$emptyCartPrompt.removeClass('hidden')
|
||||
$noAccountInfoPrompt.addClass('hidden')
|
||||
$placeOrder.addClass('disabled')
|
||||
}
|
||||
else {
|
||||
logger.debug("cart has " + carts.length + " items in it")
|
||||
$orderPrompt.removeClass('hidden')
|
||||
$emptyCartPrompt.addClass('hidden')
|
||||
$noAccountInfoPrompt.addClass('hidden')
|
||||
$placeOrder.removeClass('disabled').on('click', placeOrder)
|
||||
|
||||
var planPricing = {}
|
||||
|
||||
context._.each(carts, function(cart) {
|
||||
var priceElement = $screen.find('.order-right-page .plan[data-plan-code="' + cart.product_info.plan_code +'"]')
|
||||
|
||||
if(priceElement.length == 0) {
|
||||
logger.error("unable to find price element for " + cart.product_info.plan_code, cart);
|
||||
app.notify({title: "Error Encountered", text: "Unable to find plan info for " + cart.product_info.plan_code})
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.debug("creating recurly pricing element for plan: " + cart.product_info.plan_code)
|
||||
var pricing = context.recurly.Pricing();
|
||||
pricing.plan_code = cart.product_info.plan_code;
|
||||
pricing.resolved = false;
|
||||
pricing.effective_quantity = cart.product_info.quantity - cart.product_info.marked_for_redeem
|
||||
planPricing[pricing.plan_code] = pricing;
|
||||
|
||||
// this is called when the plan is resolved against Recurly. It will have tax info, which is the only way we can get it.
|
||||
pricing.on('change', function(price) {
|
||||
|
||||
var resolvedPrice = planPricing[this.plan_code];
|
||||
if(!resolvedPrice) {
|
||||
logger.error("unable to find price info in storage")
|
||||
app.notify({title: "Error Encountered", text: "Unable to find plan info in storage"})
|
||||
return;
|
||||
}
|
||||
else {
|
||||
logger.debug("pricing resolved for plan: " + this.plan_code)
|
||||
}
|
||||
resolvedPrice.resolved = true;
|
||||
|
||||
var allResolved = true;
|
||||
var totalTax = 0;
|
||||
var totalPrice = 0;
|
||||
|
||||
// let's see if all plans have been resolved via API; and add up total price and taxes for display
|
||||
$.each(planPricing, function(plan_code, priceObject) {
|
||||
logger.debug("resolved recurly priceObject", priceObject)
|
||||
|
||||
if(!priceObject.resolved) {
|
||||
allResolved = false;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
var unitTax = Number(priceObject.price.now.tax) * priceObject.effective_quantity;
|
||||
totalTax += unitTax;
|
||||
|
||||
var totalUnitPrice = Number(priceObject.price.now.total) * priceObject.effective_quantity;
|
||||
totalPrice += totalUnitPrice;
|
||||
}
|
||||
})
|
||||
|
||||
if(allResolved) {
|
||||
$screen.find('.order-right-page .order-items-value.taxes').text('$' + totalTax.toFixed(2))
|
||||
$screen.find('.order-right-page .order-items-value.grand-total').text('$' + totalPrice.toFixed(2))
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("still waiting on more plans to resolve")
|
||||
}
|
||||
})
|
||||
pricing.attach(priceElement.eq(0))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function moveToPaymentInfo() {
|
||||
context.location = '/client#/checkoutPayment';
|
||||
return false;
|
||||
}
|
||||
|
||||
function placeOrder(e) {
|
||||
e.preventDefault();
|
||||
$screen.find(".place-order").off('click').addClass('disabled')
|
||||
$("#order_error").text('').addClass("hidden")
|
||||
rest.placeOrder()
|
||||
.done(moveToThanks)
|
||||
.fail(orderErrorHandling);
|
||||
}
|
||||
|
||||
|
||||
function orderErrorHandling(xhr, ajaxOptions, thrownError) {
|
||||
if (xhr && xhr.responseJSON) {
|
||||
var message = "Error submitting payment: "
|
||||
$.each(xhr.responseJSON.errors, function (key, error) {
|
||||
message += key + ": " + error
|
||||
})
|
||||
$("#order_error").text(message).removeClass("hidden")
|
||||
}
|
||||
else {
|
||||
$("#order_error").text(xhr.responseText).removeClass("hidden")
|
||||
}
|
||||
$screen.find(".place-order").on('click', placeOrder).removeClass('disabled')
|
||||
}
|
||||
|
||||
function moveToThanks(purchaseResponse) {
|
||||
$("#order_error").addClass("hidden")
|
||||
$orderPanel.addClass("hidden")
|
||||
$thanksPanel.removeClass("hidden")
|
||||
jamTrackUtils.checkShoppingCart()
|
||||
handleJamTracksPurchased(purchaseResponse.jam_tracks)
|
||||
}
|
||||
|
||||
function handleJamTracksPurchased(jamTracks) {
|
||||
// were any JamTracks purchased?
|
||||
var jamTracksPurchased = jamTracks && jamTracks.length > 0;
|
||||
if(jamTracksPurchased) {
|
||||
if(gon.isNativeClient) {
|
||||
startDownloadJamTracks(jamTracks)
|
||||
}
|
||||
else {
|
||||
$jamTrackInBrowser.removeClass('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startDownloadJamTracks(jamTracks) {
|
||||
// there can be multiple purchased JamTracks, so we cycle through them
|
||||
|
||||
purchasedJamTracks = jamTracks;
|
||||
|
||||
// populate list of jamtracks purchased, that we will iterate through graphically
|
||||
context._.each(jamTracks, function(jamTrack) {
|
||||
var downloadJamTrack = new context.JK.DownloadJamTrack(app, jamTrack, 'small');
|
||||
var $purchasedJamTrack = $(context._.template(
|
||||
$templatePurchasedJamTrack.html(),
|
||||
jamTrack,
|
||||
{variable: 'data'}
|
||||
));
|
||||
|
||||
$purchasedJamTracks.append($purchasedJamTrack)
|
||||
|
||||
// show it on the page
|
||||
$purchasedJamTrack.append(downloadJamTrack.root)
|
||||
|
||||
downloadJamTracks.push(downloadJamTrack)
|
||||
})
|
||||
|
||||
iteratePurchasedJamTracks();
|
||||
}
|
||||
|
||||
function iteratePurchasedJamTracks() {
|
||||
if(purchasedJamTrackIterator < purchasedJamTracks.length ) {
|
||||
var downloadJamTrack = downloadJamTracks[purchasedJamTrackIterator++];
|
||||
|
||||
// make sure the 'purchasing JamTrack' section can be seen
|
||||
$purchasedJamTrack.removeClass('hidden');
|
||||
|
||||
// the widget indicates when it gets to any transition; we can hide it once it reaches completion
|
||||
$(downloadJamTrack).on(EVENTS.JAMTRACK_DOWNLOADER_STATE_CHANGED, function(e, data) {
|
||||
|
||||
if(data.state == downloadJamTrack.states.synchronized) {
|
||||
logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " synchronized;")
|
||||
//downloadJamTrack.root.remove();
|
||||
downloadJamTrack.destroy();
|
||||
|
||||
// go to the next JamTrack
|
||||
iteratePurchasedJamTracks()
|
||||
}
|
||||
})
|
||||
|
||||
logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " downloader initializing")
|
||||
|
||||
// kick off the download JamTrack process
|
||||
downloadJamTrack.init()
|
||||
|
||||
// XXX style-test code
|
||||
// downloadJamTrack.transitionError("package-error", "The server failed to create your package.")
|
||||
|
||||
}
|
||||
else {
|
||||
logger.debug("done iterating over purchased JamTracks")
|
||||
$purchasedJamTrackHeader.text('All purchased JamTracks have been downloaded successfully! You can now play them in a session.')
|
||||
}
|
||||
}
|
||||
|
||||
function clearOrderPage() {
|
||||
$orderContent.empty();
|
||||
}
|
||||
|
||||
function renderNavigation() {
|
||||
$navigation.html("");
|
||||
var navigationHtml = $(
|
||||
context._.template(
|
||||
$('#template-checkout-navigation').html(),
|
||||
{current: step},
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
|
||||
$navigation.append(navigationHtml);
|
||||
}
|
||||
|
||||
function events() {
|
||||
$backBtn.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
context.location = '/client#/checkoutPayment'
|
||||
})
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow,
|
||||
'beforeHide': beforeHide
|
||||
};
|
||||
app.bindScreen('checkoutOrder', screenBindings);
|
||||
|
||||
$screen = $("#checkoutOrderScreen");
|
||||
$navigation = $screen.find(".checkout-navigation-bar");
|
||||
$templateOrderContent = $("#template-order-content");
|
||||
$templatePurchasedJamTrack = $('#template-purchased-jam-track');
|
||||
$orderPanel = $screen.find(".order-panel");
|
||||
$thanksPanel = $screen.find(".thanks-panel");
|
||||
$jamTrackInBrowser = $screen.find(".thanks-detail.jam-tracks-in-browser");
|
||||
$purchasedJamTrack = $thanksPanel.find(".thanks-detail.purchased-jam-track");
|
||||
$purchasedJamTrackHeader = $purchasedJamTrack.find(".purchased-jam-track-header");
|
||||
$purchasedJamTracks = $purchasedJamTrack.find(".purchased-list")
|
||||
$backBtn = $screen.find('.back');
|
||||
$orderPrompt = $screen.find('.order-prompt');
|
||||
$emptyCartPrompt = $screen.find('.empty-cart-prompt');
|
||||
$noAccountInfoPrompt = $screen.find('.no-account-info-prompt');
|
||||
$orderContent = $orderPanel.find(".order-content");
|
||||
|
||||
if ($screen.length == 0) throw "$screen must be specified";
|
||||
if ($navigation.length == 0) throw "$navigation must be specified";
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})
|
||||
(window, jQuery);
|
||||
|
|
@ -0,0 +1,667 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.CheckoutPaymentScreen = function(app) {
|
||||
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var logger = context.JK.logger;
|
||||
var jamTrackUtils = context.JK.JamTrackUtils;
|
||||
|
||||
var $screen = null;
|
||||
var $navigation = null;
|
||||
var $billingInfo = null;
|
||||
var $shippingInfo = null;
|
||||
var $paymentMethod = null;
|
||||
var $shippingAddress = null;
|
||||
var $shippingAsBilling = null;
|
||||
var $paymentInfoPanel = null;
|
||||
var $accountSignup = null;
|
||||
var userDetail = null;
|
||||
var step = null;
|
||||
var billing_info = null;
|
||||
var shipping_info = null;
|
||||
var shipping_as_billing = null;
|
||||
var $reuseExistingCard = null;
|
||||
var $reuseExistingCardChk = null;
|
||||
var $existingCardEndsWith = null;
|
||||
var $newCardInfo = null;
|
||||
var selectCountry = null;
|
||||
var selectCountryLoaded = false;
|
||||
var $freeJamTrackPrompt = null;
|
||||
var $noFreeJamTrackPrompt = null;
|
||||
|
||||
function afterShow() {
|
||||
|
||||
beforeShowPaymentInfo();
|
||||
}
|
||||
|
||||
function beforeShowPaymentInfo() {
|
||||
step = 2;
|
||||
renderNavigation();
|
||||
renderAccountInfo();
|
||||
}
|
||||
|
||||
|
||||
function renderAccountInfo() {
|
||||
$reuseExistingCard.addClass('hidden');
|
||||
$newCardInfo.removeClass('hidden');
|
||||
$freeJamTrackPrompt.addClass('hidden');
|
||||
$noFreeJamTrackPrompt.addClass('hidden');
|
||||
$("#payment_error").addClass('hidden').text('')
|
||||
|
||||
var selectCountryReady = selectCountry.ready();
|
||||
if(!selectCountryReady) {
|
||||
// one time init of country dropdown
|
||||
selectCountryReady = selectCountry.load('US', null, null);
|
||||
}
|
||||
|
||||
selectCountryReady.done(function() {
|
||||
var user = rest.getUserDetail()
|
||||
if(user) {
|
||||
user.done(populateAccountInfo).error(app.ajaxError);
|
||||
}
|
||||
else {
|
||||
$reuseExistingCardChk.iCheck('uncheck').attr('checked', false)
|
||||
if(gon.global.one_free_jamtrack_per_user) {
|
||||
$freeJamTrackPrompt.removeClass('hidden')
|
||||
}
|
||||
else {
|
||||
$noFreeJamTrackPrompt.removeClass('hidden')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function populateAccountInfo(user) {
|
||||
userDetail = user;
|
||||
|
||||
$reuseExistingCardChk.iCheck(userDetail.reuse_card && userDetail.has_recurly_account ? 'check' : 'uncheck').attr('checked', userDetail.reuse_card)
|
||||
|
||||
// show appropriate prompt text based on whether user has a free jamtrack
|
||||
if(user.free_jamtrack) {
|
||||
$freeJamTrackPrompt.removeClass('hidden')
|
||||
}
|
||||
else {
|
||||
$noFreeJamTrackPrompt.removeClass('hidden')
|
||||
}
|
||||
|
||||
if (userDetail.has_recurly_account) {
|
||||
|
||||
rest.getBillingInfo()
|
||||
.done(function(response) {
|
||||
|
||||
if(userDetail.reuse_card) {
|
||||
$reuseExistingCard.removeClass('hidden');
|
||||
toggleReuseExistingCard.call($reuseExistingCardChk)
|
||||
$existingCardEndsWith.text(response.billing_info.last_four);
|
||||
}
|
||||
|
||||
var isSameAsShipping = true // jamTrackUtils.compareAddress(response.billing_info, response.address);
|
||||
|
||||
$shippingAsBilling.iCheck(isSameAsShipping ? 'check' : 'uncheck').attr('checked', isSameAsShipping)
|
||||
|
||||
$billingInfo.find("#billing-first-name").val(response.billing_info.first_name);
|
||||
$billingInfo.find("#billing-last-name").val(response.billing_info.last_name);
|
||||
$billingInfo.find("#billing-address1").val(response.billing_info.address1);
|
||||
$billingInfo.find("#billing-address2").val(response.billing_info.address2);
|
||||
$billingInfo.find("#billing-city").val(response.billing_info.city);
|
||||
$billingInfo.find("#billing-state").val(response.billing_info.state);
|
||||
$billingInfo.find("#billing-zip").val(response.billing_info.zip);
|
||||
$billingInfo.find("#billing-country").val(response.billing_info.country);
|
||||
|
||||
//$shippingAddress.find("#shipping-first-name").val(response.billing_info.first_name);
|
||||
//$shippingAddress.find("#shipping-last-name").val(response.billing_info.last_name);
|
||||
//$shippingAddress.find("#shipping-address1").val(response.address.address1);
|
||||
//$shippingAddress.find("#shipping-address2").val(response.address.address2);
|
||||
//$shippingAddress.find("#shipping-city").val(response.address.city);
|
||||
//$shippingAddress.find("#shipping-state").val(response.address.state);
|
||||
//$shippingAddress.find("#shipping-zip").val(response.address.zip);
|
||||
//$shippingAddress.find("#shipping-country").val(response.address.country);
|
||||
|
||||
})
|
||||
.error(app.ajaxError);
|
||||
}
|
||||
else {
|
||||
$billingInfo.find("#billing-first-name").val(userDetail.first_name);
|
||||
$billingInfo.find("#billing-last-name").val(userDetail.last_name);
|
||||
$billingInfo.find("#billing-city").val(userDetail.city);
|
||||
$billingInfo.find("#billing-state").val(userDetail.state);
|
||||
$billingInfo.find("#billing-country").val(userDetail.country);
|
||||
|
||||
$shippingAddress.find("#shipping-first-name").val(userDetail.first_name);
|
||||
$shippingAddress.find("#shipping-last-name").val(userDetail.last_name);
|
||||
$shippingAddress.find("#shipping-city").val(userDetail.city);
|
||||
$shippingAddress.find("#shipping-state").val(userDetail.state);
|
||||
$shippingAddress.find("#shipping-country").val(userDetail.country);
|
||||
}
|
||||
}
|
||||
|
||||
function beforeShow(data) {
|
||||
// XXX : style-test code
|
||||
// moveToThanks({jam_tracks: [{id: 14, jam_track_right_id: 11, name: 'Back in Black'}, {id: 15, jam_track_right_id: 11, name: 'In Bloom'}, {id: 16, jam_track_right_id: 11, name: 'Love Bird Supreme'}]});
|
||||
}
|
||||
|
||||
function beforeHide() {
|
||||
|
||||
}
|
||||
|
||||
function beforeHide() {
|
||||
|
||||
}
|
||||
|
||||
// TODO: Refactor: this function is long and fraught with many return points.
|
||||
function next(e) {
|
||||
$paymentInfoPanel.find('.error-text').remove();
|
||||
$paymentInfoPanel.find('.error').removeClass('error');
|
||||
e.preventDefault();
|
||||
$("#payment_error").addClass("hidden").text('')
|
||||
|
||||
var reuse_card_this_time = $reuseExistingCardChk.is(':checked');
|
||||
var reuse_card_next_time = $paymentMethod.find('#save-card').is(':checked');
|
||||
|
||||
// validation
|
||||
var billing_first_name = $billingInfo.find("#billing-first-name").val();
|
||||
var billing_last_name = $billingInfo.find("#billing-last-name").val();
|
||||
var billing_address1 = $billingInfo.find("#billing-address1").val();
|
||||
var billing_address2 = $billingInfo.find("#billing-address2").val();
|
||||
var billing_city = $billingInfo.find("#billing-city").val();
|
||||
var billing_state = $billingInfo.find("#billing-state").val();
|
||||
var billing_zip = $billingInfo.find("#billing-zip").val();
|
||||
var billing_country = $billingInfo.find("#billing-country").val();
|
||||
|
||||
var billingInfoValid = true;
|
||||
if (!billing_first_name) {
|
||||
$billingInfo.find('#divBillingFirstName .error-text').remove();
|
||||
$billingInfo.find('#divBillingFirstName').addClass("error").addClass("transparent");
|
||||
$billingInfo.find('#billing-first-name').after("<ul class='error-text'><li>First Name is required</li></ul>");
|
||||
|
||||
logger.info("no billing first name");
|
||||
billingInfoValid = false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingFirstName').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_last_name) {
|
||||
$billingInfo.find('#divBillingLastName .error-text').remove();
|
||||
$billingInfo.find('#divBillingLastName').addClass("error").addClass("transparent");
|
||||
$billingInfo.find('#billing-last-name').after("<ul class='error-text'><li>Last Name is required</li></ul>");
|
||||
|
||||
logger.info("no billing last name");
|
||||
billingInfoValid = false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingLastName').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_address1) {
|
||||
$billingInfo.find('#divBillingAddress1 .error-text').remove();
|
||||
$billingInfo.find('#divBillingAddress1').addClass("error").addClass("transparent");
|
||||
$billingInfo.find('#billing-address1').after("<ul class='error-text'><li>Address is required</li></ul>");
|
||||
|
||||
logger.info("no billing address line 1");
|
||||
billingInfoValid = false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingAddress1').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_zip) {
|
||||
$billingInfo.find('#divBillingZip .error-text').remove();
|
||||
$billingInfo.find('#divBillingZip').addClass("error").addClass("transparent");
|
||||
$billingInfo.find('#billing-zip').after("<ul class='error-text'><li>Zip Code is required</li></ul>");
|
||||
|
||||
logger.info("no billing zip");
|
||||
billingInfoValid = false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingZip').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_state) {
|
||||
$billingInfo.find('#divBillingState .error-text').remove();
|
||||
$billingInfo.find('#divBillingState').addClass("error").addClass("transparent");
|
||||
$billingInfo.find('#billing-state').after("<ul class='error-text'><li>State is required</li></ul>");
|
||||
|
||||
logger.info("no billing state");
|
||||
billingInfoValid = false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingState').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_city) {
|
||||
$billingInfo.find('#divBillingCity .error-text').remove();
|
||||
$billingInfo.find('#divBillingCity').addClass("error").addClass("transparent");
|
||||
$billingInfo.find('#billing-city').after("<ul class='error-text'><li>City is required</li></ul>");
|
||||
|
||||
logger.info("no billing city");
|
||||
billingInfoValid = false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingCity').removeClass("error");
|
||||
}
|
||||
|
||||
if (!billing_country) {
|
||||
$billingInfo.find('#divBillingCountry .error-text').remove();
|
||||
$billingInfo.find('#divBillingCountry').addClass("error").addClass("transparent");
|
||||
$billingInfo.find('#billing-country').after("<ul class='error-text'><li>Country is required</li></ul>");
|
||||
|
||||
logger.info("no billing country");
|
||||
billingInfoValid = false;
|
||||
}
|
||||
else {
|
||||
$billingInfo.find('#divBillingCountry').removeClass("error");
|
||||
}
|
||||
|
||||
/**
|
||||
shipping_as_billing = $shippingAsBilling.is(":checked");
|
||||
var shipping_first_name, shipping_last_name, shipping_address1, shipping_address2;
|
||||
var shipping_city, shipping_state, shipping_zip, shipping_country;
|
||||
|
||||
if (!shipping_as_billing) {
|
||||
shipping_first_name = $shippingAddress.find("#shipping-first-name").val();
|
||||
shipping_last_name = $shippingAddress.find("#shipping-last-name").val();
|
||||
shipping_address1 = $shippingAddress.find("#shipping-address1").val();
|
||||
shipping_address2 = $shippingAddress.find("#shipping-address2").val();
|
||||
shipping_city = $shippingAddress.find("#shipping-city").val();
|
||||
shipping_state = $shippingAddress.find("#shipping-state").val();
|
||||
shipping_zip = $shippingAddress.find("#shipping-zip").val();
|
||||
shipping_country = $shippingAddress.find("#shipping-country").val();
|
||||
|
||||
if (!shipping_first_name) {
|
||||
$shippingAddress.find('#divShippingFirstName .error-text').remove();
|
||||
$shippingAddress.find('#divShippingFirstName').addClass("error").addClass("transparent");
|
||||
$shippingAddress.find('#shipping-first-name').after("<ul class='error-text'><li>First Name is required</li></ul>");
|
||||
|
||||
logger.info("no address first name");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingFirstName').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_last_name) {
|
||||
$shippingAddress.find('#divShippingLastName .error-text').remove();
|
||||
$shippingAddress.find('#divShippingLastName').addClass("error").addClass("transparent");
|
||||
$shippingAddress.find('#shipping-last-name').after("<ul class='error-text'><li>Last Name is required</li></ul>");
|
||||
|
||||
logger.info("no last name");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingLastName').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_address1) {
|
||||
$shippingAddress.find('#divShippingAddress1 .error-text').remove();
|
||||
$shippingAddress.find('#divShippingAddress1').addClass("error").addClass("transparent");
|
||||
$shippingAddress.find('#shipping-address1').after("<ul class='error-text'><li>Address is required</li></ul>");
|
||||
|
||||
logger.info("no shipping address 1");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingAddress1').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_zip) {
|
||||
$shippingAddress.find('#divShippingZip .error-text').remove();
|
||||
$shippingAddress.find('#divShippingZip').addClass("error").addClass("transparent");
|
||||
$shippingAddress.find('#shipping-zip').after("<ul class='error-text'><li>Zip code is required</li></ul>");
|
||||
|
||||
logger.info("no shipping address 2");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingZip').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_state) {
|
||||
$shippingAddress.find('#divShippingState .error-text').remove();
|
||||
$shippingAddress.find('#divShippingState').addClass("error").addClass("transparent");
|
||||
$shippingAddress.find('#shipping-zip').after("<ul class='error-text'><li>State is required</li></ul>");
|
||||
|
||||
logger.info("no shipping state");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingState').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_city) {
|
||||
$shippingAddress.find('#divShippingCity .error-text').remove();
|
||||
$shippingAddress.find('#divShippingCity').addClass("error").addClass("transparent");
|
||||
$shippingAddress.find('#shipping-city').after("<ul class='error-text'><li>City is required</li></ul>");
|
||||
|
||||
logger.info("no shipping city");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingInfo.find('#divShippingCity').removeClass("error");
|
||||
}
|
||||
|
||||
if (!shipping_country) {
|
||||
$shippingAddress.find('#divShippingCountry .error-text').remove();
|
||||
$shippingAddress.find('#divShippingCountry').addClass("error").addClass("transparent");
|
||||
$shippingAddress.find('#shipping-country').after("<ul class='error-text'><li>Country is required</li></ul>");
|
||||
|
||||
logger.info("no shipping country");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$shippingAddress.find('#divShippingCountry').removeClass("error");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
var card_name = $paymentMethod.find("#card-name").val();
|
||||
var card_number = $paymentMethod.find("#card-number").val();
|
||||
var card_year = $paymentMethod.find("#card_expire-date_1i").val();
|
||||
var card_month = $paymentMethod.find("#card_expire-date_2i").val();
|
||||
var card_verify = $paymentMethod.find("#card-verify").val();
|
||||
|
||||
/**
|
||||
if (!card_name) {
|
||||
$paymentMethod.find('#divCardName .error-text').remove();
|
||||
$paymentMethod.find('#divCardName').addClass("error").addClass("transparent");
|
||||
$paymentMethod.find('#card-name').after("<ul class='error-text'><li>Card Name is required</li></ul>");
|
||||
return false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardName').removeClass("error");
|
||||
}*/
|
||||
|
||||
// don't valid card form fields when reuse card selected
|
||||
if(!reuse_card_this_time) {
|
||||
if (!card_number) {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error").addClass("transparent");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>Card Number is required</li></ul>");
|
||||
logger.info("no card number");
|
||||
billingInfoValid = false;
|
||||
} else if (!$.payment.validateCardNumber(card_number)) {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error").addClass("transparent");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>Card Number is not valid</li></ul>");
|
||||
logger.info("invalid card number");
|
||||
billingInfoValid = false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardNumber').removeClass("error");
|
||||
}
|
||||
|
||||
if (!$.payment.validateCardExpiry(card_month, card_year)) {
|
||||
$paymentMethod.find('#divCardExpiry .error-text').remove();
|
||||
$paymentMethod.find('#divCardExpiry').addClass("error").addClass("transparent");
|
||||
$paymentMethod.find('#card-expiry').after("<ul class='error-text'><li>Card Number is not valid</li></ul>");
|
||||
logger.info("invalid card expiry");
|
||||
billingInfoValid = false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardExpiry').removeClass("error");
|
||||
}
|
||||
|
||||
if (!card_verify) {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error").addClass("transparent");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>Card Verification Value is required</li></ul>");
|
||||
|
||||
logger.info("no card verify");
|
||||
billingInfoValid = false;
|
||||
} else if (!$.payment.validateCardCVC(card_verify)) {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error").addClass("transparent");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>Card Verification Value is not valid.</li></ul>");
|
||||
|
||||
logger.info("bad card CVC");
|
||||
billingInfoValid = false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardVerify').removeClass("error");
|
||||
}
|
||||
}
|
||||
|
||||
if(!billingInfoValid) {
|
||||
logger.debug("billing info is invalid. returning");
|
||||
return false;
|
||||
}
|
||||
|
||||
billing_info = {};
|
||||
shipping_info = {};
|
||||
billing_info.first_name = billing_first_name;
|
||||
billing_info.last_name = billing_last_name;
|
||||
billing_info.address1 = billing_address1;
|
||||
billing_info.address2 = billing_address2;
|
||||
billing_info.city = billing_city;
|
||||
billing_info.state = billing_state;
|
||||
billing_info.country = billing_country;
|
||||
billing_info.zip = billing_zip;
|
||||
billing_info.number = card_number;
|
||||
billing_info.month = card_month;
|
||||
billing_info.year = card_year;
|
||||
billing_info.verification_value = card_verify;
|
||||
|
||||
/**
|
||||
if (shipping_as_billing) {
|
||||
shipping_info = $.extend({},billing_info);
|
||||
delete shipping_info.number;
|
||||
delete shipping_info.month;
|
||||
delete shipping_info.year;
|
||||
delete shipping_info.verification_value;
|
||||
} else {
|
||||
shipping_info.first_name = shipping_first_name;
|
||||
shipping_info.last_name = shipping_last_name;
|
||||
shipping_info.address1 = shipping_address1;
|
||||
shipping_info.address2 = shipping_address2;
|
||||
shipping_info.city = shipping_city;
|
||||
shipping_info.state = shipping_state;
|
||||
shipping_info.country = shipping_country;
|
||||
shipping_info.zip = shipping_zip;
|
||||
}*/
|
||||
|
||||
var email = null;
|
||||
var password = null;
|
||||
var terms = false;
|
||||
var isLoggedIn = context.JK.currentUserId;
|
||||
if(!isLoggedIn) {
|
||||
email = $accountSignup.find('input[name="email"]').val()
|
||||
password = $accountSignup.find('input[name="password"]').val()
|
||||
terms = $accountSignup.find('input[name="terms-of-service"]').is(':checked');
|
||||
}
|
||||
|
||||
$screen.find("#payment-info-next").addClass("disabled");
|
||||
$screen.find("#payment-info-next").off("click");
|
||||
rest.createRecurlyAccount({billing_info: billing_info, terms_of_service: terms, email: email, password: password, reuse_card_this_time: reuse_card_this_time, reuse_card_next_time: reuse_card_next_time})
|
||||
.done(function() {
|
||||
$screen.find("#payment-info-next").on("click", next);
|
||||
|
||||
if(isLoggedIn) {
|
||||
context.location = '/client#/checkoutOrder'
|
||||
}
|
||||
else {
|
||||
// this means the account was created; we need to reload the page for this to take effect
|
||||
context.JK.currentUserId = 'something' // this is to trick layout.js from getting involved and redirecting to home screen
|
||||
context.location = '/client#/checkoutOrder'
|
||||
context.location.reload()
|
||||
}
|
||||
})
|
||||
.fail(errorHandling)
|
||||
.always(function(){
|
||||
$screen.find("#payment-info-next").removeClass("disabled");
|
||||
})
|
||||
}
|
||||
|
||||
function errorHandling(xhr, ajaxOptions, thrownError) {
|
||||
logger.debug("error handling", xhr.responseJSON)
|
||||
if(xhr.responseJSON && xhr.responseJSON.errors) {
|
||||
$.each(xhr.responseJSON.errors, function(key, error) {
|
||||
if (key == 'number') {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error").addClass("transparent");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if (key == 'verification_value') {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error").addClass("transparent");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if(key == 'email') {
|
||||
var $email = $accountSignup.find('input[name="email"]')
|
||||
var $field = $email.closest('.field')
|
||||
$field.find('.error-text').remove()
|
||||
$field.addClass("error").addClass("transparent");
|
||||
$email.after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if(key == 'password') {
|
||||
var $password = $accountSignup.find('input[name="password"]')
|
||||
var $field = $password.closest('.field')
|
||||
$field.find('.error-text').remove()
|
||||
$field.addClass("error").addClass("transparent");
|
||||
$password.after("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if(key == 'terms_of_service') {
|
||||
var $terms = $accountSignup.find('input[name="terms-of-service"]')
|
||||
var $field = $terms.closest('.field')
|
||||
$field.find('.error-text').remove()
|
||||
$field.addClass("error").addClass("transparent");
|
||||
$accountSignup.find('.terms-of-service-label-holder').append("<ul class='error-text'><li>" + error + "</li></ul>");
|
||||
}
|
||||
else if(key == 'message') {
|
||||
$("#payment_error").text(error).removeClass('hidden')
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
$("#payment_error").text(xhr.responseText).removeClass('hidden')
|
||||
}
|
||||
|
||||
|
||||
$screen.find("#payment-info-next").on('click', next);
|
||||
}
|
||||
|
||||
function beforeShowOrder() {
|
||||
step = 3;
|
||||
renderNavigation();
|
||||
populateOrderPage();
|
||||
}
|
||||
|
||||
|
||||
function populateOrderPage() {
|
||||
|
||||
rest.getShoppingCarts()
|
||||
.done(renderOrderPage)
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function toggleShippingAsBilling(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var shipping_as_billing = $(e.target).is(':checked');
|
||||
|
||||
if (!shipping_as_billing) {
|
||||
$shippingAddress.removeClass("hidden");
|
||||
}
|
||||
else {
|
||||
$shippingAddress.addClass("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleReuseExistingCard(e) {
|
||||
if(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
logger.debug("toggle reuse existing card")
|
||||
|
||||
var reuse_existing = $(this).is(':checked');
|
||||
|
||||
$('#billing-first-name').prop('disabled', reuse_existing);
|
||||
$('#billing-last-name').prop('disabled', reuse_existing);
|
||||
$('#billing-address1').prop('disabled', reuse_existing);
|
||||
$('#billing-address2').prop('disabled', reuse_existing);
|
||||
$('#billing-city').prop('disabled', reuse_existing);
|
||||
$('#billing-state').prop('disabled', reuse_existing);
|
||||
$('#billing-zip').prop('disabled', reuse_existing);
|
||||
$('#billing-country').prop('disabled', reuse_existing);
|
||||
|
||||
$('#card-name').prop('disabled', reuse_existing);
|
||||
$('#card-number').prop('disabled', reuse_existing);
|
||||
$('#card_expire-date_1i').prop('disabled', reuse_existing);
|
||||
$('#card_expire-date_2i').prop('disabled', reuse_existing);
|
||||
$('#card-verify').prop('disabled', reuse_existing);
|
||||
|
||||
}
|
||||
|
||||
function events() {
|
||||
$screen.find("#payment-info-next").on('click', next);
|
||||
$shippingAsBilling.on('ifChanged', toggleShippingAsBilling);
|
||||
$reuseExistingCardChk.on('ifChanged', toggleReuseExistingCard);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
|
||||
}
|
||||
|
||||
function renderNavigation() {
|
||||
$navigation.html("");
|
||||
var navigationHtml = $(
|
||||
context._.template(
|
||||
$('#template-checkout-navigation').html(),
|
||||
{current: step},
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
|
||||
$navigation.append(navigationHtml);
|
||||
}
|
||||
|
||||
function initializeControls() {
|
||||
$("form.payment-info").addClass(context.JK.currentUserId ? 'signed-in' : 'not-signed-in').iCheck({
|
||||
checkboxClass: 'icheckbox_minimal',
|
||||
radioClass: 'iradio_minimal',
|
||||
inheritClass: true
|
||||
});
|
||||
|
||||
// Use jquery.payment to limit characters and length:
|
||||
$paymentMethod.find("#card-number").payment('formatCardNumber');
|
||||
$paymentMethod.find("#card-verify").payment('formatCardCVC');
|
||||
|
||||
selectCountry = new context.JK.SelectLocation($('#billing-country'), null, null, app, false)
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow,
|
||||
'beforeHide' : beforeHide
|
||||
};
|
||||
app.bindScreen('checkoutPayment', screenBindings);
|
||||
|
||||
$screen = $("#checkoutPaymentScreen");
|
||||
$paymentInfoPanel = $screen.find("#checkout-payment-info");
|
||||
$navigation = $screen.find(".checkout-navigation-bar");
|
||||
$billingInfo = $paymentInfoPanel.find(".billing-address");
|
||||
$shippingInfo = $paymentInfoPanel.find(".shipping-address");
|
||||
$paymentMethod = $paymentInfoPanel.find(".payment-method");
|
||||
$accountSignup = $paymentInfoPanel.find('.jamkazam-account-signup')
|
||||
$shippingAddress = $paymentInfoPanel.find(".shipping-address-detail");
|
||||
$shippingAsBilling = $paymentInfoPanel.find("#shipping-as-billing");
|
||||
$reuseExistingCard = $paymentInfoPanel.find('.reuse-existing-card')
|
||||
$reuseExistingCardChk = $paymentInfoPanel.find('#reuse-existing-card')
|
||||
$existingCardEndsWith = $paymentInfoPanel.find('.existing-card-ends-with')
|
||||
$newCardInfo = $paymentInfoPanel.find('.new-card-info')
|
||||
$freeJamTrackPrompt = $screen.find('.payment-prompt.free-jamtrack')
|
||||
$noFreeJamTrackPrompt = $screen.find('.payment-prompt.no-free-jamtrack')
|
||||
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($navigation.length == 0) throw "$navigation must be specified";
|
||||
|
||||
initializeControls();
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})(window,jQuery);
|
||||
|
|
@ -14,54 +14,77 @@
|
|||
var $password = null;
|
||||
var $signinBtn = null;
|
||||
var $signupBtn = null;
|
||||
var $inputElements = null;
|
||||
var $contentHolder = null;
|
||||
var $btnNext = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
renderNavigation();
|
||||
renderLoggedInState();
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function events() {
|
||||
$signinBtn.on('click', login);
|
||||
$signupBtn.on('click', signup);
|
||||
|
||||
function renderLoggedInState(){
|
||||
if(isLoggedIn()) {
|
||||
$contentHolder.removeClass('not-signed-in').addClass('signed-in')
|
||||
}
|
||||
else {
|
||||
$contentHolder.removeClass('signed-in').addClass('not-signed-in')
|
||||
}
|
||||
}
|
||||
|
||||
function signup(e) {
|
||||
app.layout.showDialog('signup-dialog');
|
||||
return false;
|
||||
function isLoggedIn() {
|
||||
return !!context.JK.currentUserId;
|
||||
}
|
||||
|
||||
function events() {
|
||||
$signinForm.on('submit', login);
|
||||
$signinBtn.on('click', login);
|
||||
$btnNext.on('click', moveNext);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
$signinForm.removeClass('login-error');
|
||||
|
||||
$email.val('');
|
||||
$password.val('');
|
||||
$inputElements.removeClass('login-error');
|
||||
}
|
||||
|
||||
function moveNext() {
|
||||
window.location = '/client#/checkoutPayment';
|
||||
|
||||
return false;
|
||||
}
|
||||
function login() {
|
||||
if($signinBtn.is('.disabled')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var email = $email.val();
|
||||
var password = $password.val();
|
||||
|
||||
reset();
|
||||
|
||||
$signinBtn.text('TRYING...');
|
||||
$signinBtn.text('TRYING...').addClass('disabled')
|
||||
|
||||
rest.login({email: email, password: password, remember_me: false})
|
||||
rest.login({email: email, password: password, remember_me: true})
|
||||
.done(function() {
|
||||
window.location = '/client#/order'
|
||||
window.location = '/client#/checkoutPayment'
|
||||
window.location.reload();
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
$signinForm.addClass('login-error')
|
||||
$inputElements.addClass('login-error')
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(jqXHR, "Unable to log in")
|
||||
}
|
||||
})
|
||||
.always(function() {
|
||||
$signinBtn.text('SIGN IN')
|
||||
$signinBtn.text('SIGN IN').removeClass('disabled')
|
||||
})
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function renderNavigation() {
|
||||
|
|
@ -83,15 +106,17 @@
|
|||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
app.bindScreen('signin', screenBindings);
|
||||
app.bindScreen('checkoutSignin', screenBindings);
|
||||
|
||||
$screen = $("#signInScreen");
|
||||
$screen = $("#checkoutSignInScreen");
|
||||
$navigation = $screen.find(".checkout-navigation-bar");
|
||||
$signinForm = $screen.find(".signin-form");
|
||||
$signinBtn = $signinForm.find('.signin-submit');
|
||||
$email = $signinForm.find('input[name="session[email]"]');
|
||||
$password = $signinForm.find('input[name="session[password]"]');
|
||||
$signupBtn = $signinForm.find('.show-signup-dialog');
|
||||
$email = $signinForm.find('input[name="email"]');
|
||||
$password = $signinForm.find('input[name="password"]');
|
||||
$inputElements = $signinForm.find('.input-elements');
|
||||
$contentHolder = $screen.find('.content-holder');
|
||||
$btnNext = $screen.find('.btnNext');
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($navigation.length == 0) throw "$navigation must be specified";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {};
|
||||
|
||||
# events emitted:
|
||||
# EVENTS.CHECKOUT_SIGNED_IN
|
||||
# EVENTS.CHECKOUT_SKIP_SIGN_IN
|
||||
|
||||
context.JK.CheckoutSignin = class CheckoutSignin
|
||||
constructor: (app, root) ->
|
||||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@logger = context.JK.logger
|
||||
@app = app
|
||||
@root = root
|
||||
@emailInput = @root.find('input[name="email"]')
|
||||
@passwordInput = @root.find('input[name="password"]')
|
||||
@signinBtn = @root.find('.signin-submit')
|
||||
@skipSigninBtn = @root.find('.btnNext')
|
||||
@signinForm = @root.find('form.signin-form')
|
||||
|
||||
# TODO: add Facebook login support
|
||||
|
||||
throw "no root element" if not @root.exists()
|
||||
throw "no email element" if not @emailInput.exists()
|
||||
throw "no password element" if not @passwordInput.exists()
|
||||
throw "no signin btn" if not @signinBtn.exists()
|
||||
throw "no skip signin btn" if not @skipSigninBtn.exists()
|
||||
|
||||
@signinForm.submit(@onSigninSubmit)
|
||||
@skipSigninBtn.click(@onSkipSignin)
|
||||
|
||||
removeErrors: () =>
|
||||
@signinForm.removeClass('login-error');
|
||||
|
||||
onSigninSubmit: () =>
|
||||
@logger.debug("attempting to signin")
|
||||
|
||||
@removeErrors()
|
||||
|
||||
@signinBtn.addClass('disabled')
|
||||
|
||||
email = @emailInput.val()
|
||||
password = @passwordInput.val()
|
||||
|
||||
@rest.login({email: email, password: password, remember_me: true})
|
||||
.done(@onLoginDone)
|
||||
.fail(@onLoginFail)
|
||||
|
||||
onLoginDone: () =>
|
||||
@signinBtn.removeClass('disabled')
|
||||
$(this).triggerHandler(@EVENTS.CHECKOUT_SIGNED_IN, {})
|
||||
|
||||
onLoginFail: (jqXHR) =>
|
||||
@signinBtn.removeClass('disabled')
|
||||
if jqXHR.status == 422
|
||||
@signinForm.addClass('login-error')
|
||||
else
|
||||
@app.notifyServerError(jqXHR, "Unable to log in. Try again later.")
|
||||
|
||||
onSkipSignin: () =>
|
||||
$(this).triggerHandler(@EVENTS.CHECKOUT_SKIP_SIGN_IN, {})
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.JamtrackLicenseDialog = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
var $dialog = null;
|
||||
var dialogId = 'jamtrack-license-dialog';
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$dialog = $('[layout-id="' + dialogId + '"]');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
};
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {}
|
||||
|
||||
context.JK.JamtrackPaymentHistoryDialog = class JamtrackPaymentHistoryDialog
|
||||
constructor: (@app) ->
|
||||
@rest = context.JK.Rest()
|
||||
@client = context.jamClient
|
||||
@logger = context.JK.logger
|
||||
@screen = null
|
||||
@dialogId = 'jamtrack-payment-history-dialog';
|
||||
@dialog = null;
|
||||
|
||||
initialize:() =>
|
||||
dialogBindings = {
|
||||
'beforeShow' : @beforeShow,
|
||||
'afterShow' : @afterShow
|
||||
}
|
||||
|
||||
@dialog = $('[layout-id="' + @dialogId + '"]');
|
||||
@app.bindDialog(@dialogId, dialogBindings);
|
||||
@tbody = @dialog.find("table.payment-table tbody")
|
||||
@rowTemplate = $('#template-payment-history-row').html()
|
||||
|
||||
beforeShow:() =>
|
||||
# Get payment history from jamrest
|
||||
payments = [
|
||||
{date: new Date(2013, 4, 5), amount: 372.33},
|
||||
{date: new Date(2014, 5, 5), amount: 338.44}
|
||||
]
|
||||
|
||||
@rest.getPaymentHistory()
|
||||
.done(@showPaymentHistory)
|
||||
.fail(@app.ajaxError)
|
||||
|
||||
showPaymentHistory:(data) =>
|
||||
# Turn in to HTML rows and append:
|
||||
@tbody.html("")
|
||||
if data.payments? && data.payments.length > 0
|
||||
for p in data.payments
|
||||
amt = p.amount
|
||||
amt = 0 if !amt?
|
||||
payment = {
|
||||
date: context.JK.formatDateYYYYMMDD(p.created_at)
|
||||
amount: (amt * 100).toFixed(2)
|
||||
status: p.status
|
||||
payment_method: p.payment_method.replace("_", " ")
|
||||
reference: p.reference
|
||||
}
|
||||
tr = $(context._.template(@rowTemplate, payment, { variable: 'data' }));
|
||||
@tbody.append(tr);
|
||||
else
|
||||
tr = "<tr><td colspan='5'>No payments found</td></tr>"
|
||||
@tbody.append(tr);
|
||||
|
||||
afterShow:() =>
|
||||
|
||||
showDialog:() =>
|
||||
@app.layout.showDialog(@dialogId)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.LoginRequiredDialog = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
var $dialog = null;
|
||||
var dialogId = 'login-required-dialog';
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
}
|
||||
|
||||
function events() {
|
||||
$dialog.find('.go-to-jamtracks').click(function() {
|
||||
app.layout.closeDialog(dialogId)
|
||||
context.location.href = $(this).attr('href')
|
||||
})
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$dialog = $('#' + dialogId);
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
};
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -127,6 +127,9 @@
|
|||
|
||||
var clientPreferencesDialog = new JK.ClientPreferencesDialog(app);
|
||||
clientPreferencesDialog.initialize();
|
||||
|
||||
var loginRequiredDialog = new JK.LoginRequiredDialog(app);
|
||||
loginRequiredDialog.initialize();
|
||||
}
|
||||
|
||||
// wait 10 seconds
|
||||
|
|
@ -201,8 +204,10 @@
|
|||
var user = app.user()
|
||||
if(user) {
|
||||
user.done(function(userProfile) {
|
||||
console.log("app.layout.getCurrentScreen() != 'checkoutOrderScreen'", app.layout.getCurrentScreen())
|
||||
if (userProfile.show_whats_next &&
|
||||
window.location.pathname.indexOf(gon.client_path) == 0 &&
|
||||
window.location.pathname.indexOf('/checkout') == -1 &&
|
||||
!app.layout.isDialogShowing('getting-started'))
|
||||
{
|
||||
app.layout.showDialog('getting-started');
|
||||
|
|
@ -212,13 +217,7 @@
|
|||
}
|
||||
|
||||
function initShoppingCart(app) {
|
||||
|
||||
var user = app.user()
|
||||
if(user) {
|
||||
user.done(function(userProfile) {
|
||||
context.JK.JamTrackUtils.checkShoppingCart();
|
||||
})
|
||||
}
|
||||
context.JK.JamTrackUtils.checkShoppingCart();
|
||||
}
|
||||
|
||||
})(window, jQuery);
|
||||
|
|
|
|||
|
|
@ -739,7 +739,7 @@
|
|||
}
|
||||
|
||||
function SessionOpenMetronome(bpm, click, meter, mode){
|
||||
console.log("Setting metronome BPM: ", bpm)
|
||||
logger.debug("Setting metronome BPM: ", bpm)
|
||||
metronomeActive =true
|
||||
metronomeBPM = bpm
|
||||
metronomeSound = click
|
||||
|
|
|
|||
|
|
@ -57,9 +57,11 @@
|
|||
})
|
||||
.fail(function(xhr, textStatus, errorMessage) {
|
||||
if (xhr.status === 404) {
|
||||
logger.warn("unable to list active sessions (404)")
|
||||
// swallow 404
|
||||
}
|
||||
else {
|
||||
logger.warn("unable to list active sessions")
|
||||
app.ajaxError(xhr, textStatus, errorMessage);
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
CHAT: "1"
|
||||
};
|
||||
|
||||
context.JK.AVAILABILITY_US = "United States";
|
||||
context.JK.MASTER_TRACK = "Master";
|
||||
|
||||
context.JK.EVENTS = {
|
||||
DIALOG_CLOSED : 'dialog_closed',
|
||||
SHOW_SIGNUP : 'show_signup',
|
||||
|
|
@ -47,7 +50,9 @@
|
|||
CONNECTION_DOWN: 'connection_down',
|
||||
SCREEN_CHANGED: 'screen_changed',
|
||||
JAMTRACK_DOWNLOADER_STATE_CHANGED: 'jamtrack_downloader_state',
|
||||
METRONOME_PLAYBACK_MODE_SELECTED: 'metronome_playback_mode_selected'
|
||||
METRONOME_PLAYBACK_MODE_SELECTED: 'metronome_playback_mode_selected',
|
||||
CHECKOUT_SIGNED_IN: 'checkout_signed_in',
|
||||
CHECKOUT_SKIP_SIGN_IN: 'checkout_skip_sign_in'
|
||||
};
|
||||
|
||||
context.JK.PLAYBACK_MONITOR_MODE = {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
context.JK.HomeScreen = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
var isFtueComplete = false;
|
||||
var $screen = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
|
@ -86,9 +87,20 @@
|
|||
var screenBindings = { 'beforeShow': beforeShow };
|
||||
app.bindScreen('home', screenBindings);
|
||||
events();
|
||||
$screen = $('.screen[layout-id="home"]')
|
||||
|
||||
$('.profile').on('click', function() {
|
||||
$screen.find('.profile').on('click', function() {
|
||||
var $destination = $('[layout-id="profile"]');
|
||||
if(!context.JK.currentUserId && !$destination.is('.no-login-required')) {
|
||||
// if there is no user and login is required, then stop user from clicknig through
|
||||
app.layout.showDialog('login-required-dialog')
|
||||
}
|
||||
else
|
||||
{
|
||||
context.location = '/client#/profile/' + context.JK.currentUserId;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@
|
|||
processData: false,
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(options)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function getUserDetail(options) {
|
||||
|
|
@ -1236,6 +1236,15 @@
|
|||
})
|
||||
}
|
||||
|
||||
function playJamTrack(jamTrackId) {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/jamtracks/played/' + jamTrackId,
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function closeJamTrack(options) {
|
||||
var musicSessionId = options["id"];
|
||||
delete options["id"];
|
||||
|
|
@ -1479,6 +1488,15 @@
|
|||
});
|
||||
}
|
||||
|
||||
function getPaymentHistory(options) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/recurly/payment_history',
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function getBackingTracks(options) {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
|
|
@ -1561,10 +1579,10 @@
|
|||
});
|
||||
}
|
||||
|
||||
function placeOrder(options) {
|
||||
function placeOrder() {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/recurly/place_order?' + $.param(options),
|
||||
url: '/api/recurly/place_order',
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
|
|
@ -1753,6 +1771,7 @@
|
|||
this.updateAudioLatency = updateAudioLatency;
|
||||
this.getJamtracks = getJamtracks;
|
||||
this.getPurchasedJamTracks = getPurchasedJamTracks;
|
||||
this.getPaymentHistory = getPaymentHistory;
|
||||
this.getJamTrackRight = getJamTrackRight;
|
||||
this.enqueueJamTrack = enqueueJamTrack;
|
||||
this.getBackingTracks = getBackingTracks;
|
||||
|
|
@ -1774,6 +1793,7 @@
|
|||
this.addRecordingTimeline = addRecordingTimeline;
|
||||
this.getMusicianSearchFilter = getMusicianSearchFilter;
|
||||
this.postMusicianSearchFilter = postMusicianSearchFilter;
|
||||
this.playJamTrack = playJamTrack;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,242 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {}
|
||||
|
||||
context.JK.JamTrackScreen=class JamTrackScreen
|
||||
LIMIT = 10
|
||||
instrument_logo_map = context.JK.getInstrumentIconMap24()
|
||||
|
||||
constructor: (@app) ->
|
||||
@logger = context.JK.logger
|
||||
@screen = null
|
||||
@content = null
|
||||
@scroller = null
|
||||
@genre = null
|
||||
@artist = null
|
||||
@instrument = null
|
||||
@availability = null
|
||||
@nextPager = null
|
||||
@noMoreJamtracks = null
|
||||
@currentPage = 0
|
||||
@next = null
|
||||
@currentQuery = this.defaultQuery()
|
||||
@expanded = false
|
||||
|
||||
beforeShow:(data) =>
|
||||
this.setFilterFromURL()
|
||||
this.refresh()
|
||||
|
||||
afterShow:(data) =>
|
||||
|
||||
events:() =>
|
||||
@genre.on 'change', this.search
|
||||
@artist.on 'change', this.search
|
||||
@instrument.on 'change', this.search
|
||||
@availability.on 'change', this.search
|
||||
|
||||
clearResults:() =>
|
||||
@currentPage = 0
|
||||
@content.empty()
|
||||
@noMoreJamtracks.hide()
|
||||
@next = null
|
||||
|
||||
setFilterFromURL:() =>
|
||||
# Grab parms from URL for artist, instrument, and availability
|
||||
parms=this.getParams()
|
||||
|
||||
if(parms.artist?)
|
||||
@artist.val(parms.artist)
|
||||
if(parms.instrument?)
|
||||
@instrument.val(parms.instrument)
|
||||
if(parms.availability?)
|
||||
@availability.val(parms.availability)
|
||||
window.history.replaceState({}, "", "/client#/jamtrack")
|
||||
|
||||
getParams:() =>
|
||||
params = {}
|
||||
q = window.location.href.split("?")[1]
|
||||
if q?
|
||||
q = q.split('#')[0]
|
||||
raw_vars = q.split("&")
|
||||
for v in raw_vars
|
||||
[key, val] = v.split("=")
|
||||
params[key] = decodeURIComponent(val)
|
||||
ms
|
||||
params
|
||||
|
||||
refresh:() =>
|
||||
@currentQuery = this.buildQuery()
|
||||
that = this
|
||||
rest.getJamtracks(@currentQuery).done((response) ->
|
||||
that.clearResults()
|
||||
that.handleJamtrackResponse(response)
|
||||
).fail (jqXHR) ->
|
||||
that.clearResults()
|
||||
that.noMoreJamtracks.show()
|
||||
that.app.notifyServerError jqXHR, 'Jamtrack Unavailable'
|
||||
|
||||
search:() =>
|
||||
this.refresh()
|
||||
false
|
||||
|
||||
defaultQuery:() =>
|
||||
query =
|
||||
per_page: LIMIT
|
||||
page: @currentPage+1
|
||||
if @next
|
||||
query.since = @next
|
||||
query
|
||||
|
||||
buildQuery:() =>
|
||||
@currentQuery = this.defaultQuery()
|
||||
# genre filter
|
||||
# var genres = @screen.find('#jamtrack_genre').val()
|
||||
# if (genres !== undefined) {
|
||||
# @currentQuery.genre = genres
|
||||
# }
|
||||
# instrument filter
|
||||
|
||||
instrument = @instrument.val()
|
||||
if instrument?
|
||||
@currentQuery.instrument = instrument
|
||||
|
||||
# artist filter
|
||||
art = @artist.val()
|
||||
if art?
|
||||
@currentQuery.artist = art
|
||||
|
||||
# availability filter
|
||||
availability = @availability.val()
|
||||
if availability?
|
||||
@currentQuery.availability = availability
|
||||
@currentQuery
|
||||
|
||||
handleJamtrackResponse:(response) =>
|
||||
@next = response.next
|
||||
this.renderJamtracks(response)
|
||||
if response.next == null
|
||||
# if we less results than asked for, end searching
|
||||
@scroller.infinitescroll 'pause'
|
||||
if @currentPage == 0 and response.jamtracks.length == 0
|
||||
@content.append '<div class=\'no-jamtracks-msg\'>There\'s no jamtracks.</div>'
|
||||
if @currentPage > 0
|
||||
@noMoreJamtracks.show()
|
||||
# there are bugs with infinitescroll not removing the 'loading'.
|
||||
# it's most noticeable at the end of the list, so whack all such entries
|
||||
$('.infinite-scroll-loader').remove()
|
||||
else
|
||||
@currentPage++
|
||||
this.buildQuery()
|
||||
this.registerInfiniteScroll()
|
||||
|
||||
|
||||
registerInfiniteScroll:() =>
|
||||
@scroller.infinitescroll {
|
||||
behavior: 'local'
|
||||
navSelector: '#jamtrackScreen .btn-next-pager'
|
||||
nextSelector: '#jamtrackScreen .btn-next-pager'
|
||||
binder: @scroller
|
||||
dataType: 'json'
|
||||
appendCallback: false
|
||||
prefill: false
|
||||
bufferPx: 100
|
||||
loading:
|
||||
msg: $('<div class="infinite-scroll-loader">Loading ...</div>')
|
||||
img: '/assets/shared/spinner.gif'
|
||||
path: (page) ->
|
||||
'/api/jamtracks?' + $.param(this.buildQuery())
|
||||
|
||||
}, (json, opts) ->
|
||||
this.handleJamtrackResponse(json)
|
||||
@scroller.infinitescroll 'resume'
|
||||
|
||||
playJamtrack:(e) =>
|
||||
e.preventDefault()
|
||||
|
||||
addToCartJamtrack:(e) =>
|
||||
e.preventDefault()
|
||||
params = id: $(e.target).attr('data-jamtrack-id')
|
||||
rest.addJamtrackToShoppingCart(params).done((response) ->
|
||||
context.location = '/client#/shoppingCart'
|
||||
).fail @app.ajaxError
|
||||
|
||||
licenseUSWhy:(e) =>
|
||||
e.preventDefault()
|
||||
@app.layout.showDialog 'jamtrack-availability-dialog'
|
||||
|
||||
registerEvents:() =>
|
||||
@screen.find('.jamtrack-detail-btn').on 'click', this.showJamtrackDescription
|
||||
@screen.find('.play-button').on 'click', this.playJamtrack
|
||||
@screen.find('.jamtrack-add-cart').on 'click', this.addToCartJamtrack
|
||||
@screen.find('.license-us-why').on 'click', this.licenseUSWhy
|
||||
@screen.find('.jamtrack-detail-btn').on 'click', this.toggleExpanded
|
||||
|
||||
renderJamtracks:(data) =>
|
||||
that = this
|
||||
for jamtrack in data.jamtracks
|
||||
for track in jamtrack.tracks
|
||||
continue if track.track_type=='Master'
|
||||
inst = '../assets/content/icon_instrument_default24.png'
|
||||
if track.instrument.id in instrument_logo_map
|
||||
inst = instrument_logo_map[track.instrument.id].asset
|
||||
track.instrument_url = inst
|
||||
track.instrument_desc = track.instrument.description
|
||||
if track.part != ''
|
||||
track.instrument_desc += ' (' + track.part + ')'
|
||||
|
||||
options =
|
||||
jamtrack: jamtrack
|
||||
expanded: that.expanded
|
||||
|
||||
@jamtrackItem = $(context._.template($('#template-jamtrack').html(), options, variable: 'data'))
|
||||
that.renderJamtrack(@jamtrackItem)
|
||||
this.registerEvents()
|
||||
|
||||
showJamtrackDescription:(e) =>
|
||||
e.preventDefault()
|
||||
@description = $(e.target).parent('.detail-arrow').next()
|
||||
if @description.css('display') == 'none'
|
||||
@description.show()
|
||||
else
|
||||
@description.hide()
|
||||
|
||||
toggleExpanded:() =>
|
||||
this.expanded = !this.expanded
|
||||
this.refresh()
|
||||
|
||||
renderJamtrack:(jamtrack) =>
|
||||
@content.append jamtrack
|
||||
|
||||
initialize:() =>
|
||||
screenBindings =
|
||||
'beforeShow': this.beforeShow
|
||||
'afterShow': this.afterShow
|
||||
@app.bindScreen 'jamtrack', screenBindings
|
||||
@screen = $('#jamtrack-find-form')
|
||||
@scroller = @screen.find('.content-body-scroller')
|
||||
@content = @screen.find('.jamtrack-content')
|
||||
@genre = @screen.find('#jamtrack_genre')
|
||||
@artist = @screen.find('#jamtrack_artist')
|
||||
@instrument = @screen.find('#jamtrack_instrument')
|
||||
@availability = @screen.find('#jamtrack_availability')
|
||||
@nextPager = @screen.find('a.btn-next-pager')
|
||||
@noMoreJamtracks = @screen.find('.end-of-jamtrack-list')
|
||||
if @screen.length == 0
|
||||
throw new Error('@screen must be specified')
|
||||
if @scroller.length == 0
|
||||
throw new Error('@scroller must be specified')
|
||||
if @content.length == 0
|
||||
throw new Error('@content must be specified')
|
||||
if @noMoreJamtracks.length == 0
|
||||
throw new Error('@noMoreJamtracks must be specified')
|
||||
#if(@genre.length == 0) throw new Error("@genre must be specified")
|
||||
|
||||
if @artist.length == 0
|
||||
throw new Error('@artist must be specified')
|
||||
if @instrument.length == 0
|
||||
throw new Error('@instrument must be specified')
|
||||
if @availability.length == 0
|
||||
throw new Error('@availability must be specified')
|
||||
this.events()
|
||||
|
||||
|
||||
|
|
@ -16,13 +16,18 @@ class JamTrackUtils
|
|||
@rest.getShoppingCarts().done(this.displayCartIcon)
|
||||
|
||||
displayCartIcon: (carts) =>
|
||||
cartLink = $("a[href='" + "/client#/shoppingCart" + "']")
|
||||
cartLink = $("#header-shopping-cart")
|
||||
if carts.length > 0
|
||||
cartLink.removeClass("hidden")
|
||||
else
|
||||
cartLink.addClass("hidden")
|
||||
|
||||
|
||||
compareAddress: (billing, shipping) =>
|
||||
billing.address1 == shipping.address1 &&
|
||||
billing.address2 == shipping.address2 &&
|
||||
billing.zip == shipping.zip &&
|
||||
billing.city == shipping.city &&
|
||||
billing.country == shipping.country;
|
||||
|
||||
|
||||
# global instance
|
||||
|
|
|
|||
|
|
@ -132,6 +132,9 @@
|
|||
logger.error("Unexpected ajax error: " + textStatus + ", msg:" + errorMessage);
|
||||
app.notify({title: "Oops!", text: "What you were looking for is gone now."});
|
||||
}
|
||||
else if(jqXHR.status === 403) {
|
||||
logger.debug("not logged in");
|
||||
}
|
||||
else if (jqXHR.status === 422) {
|
||||
logger.error("Unexpected ajax error: " + textStatus + ", msg: " + errorMessage + ", response: " + jqXHR.responseText);
|
||||
// present a nicer message
|
||||
|
|
@ -282,20 +285,37 @@
|
|||
|
||||
var hash = context.location.hash;
|
||||
|
||||
var screen = 'home'
|
||||
try {
|
||||
context.RouteMap.parse(hash);
|
||||
var location = context.RouteMap.parse(hash);
|
||||
screen = location.page.substring(1); // remove leading slash
|
||||
}
|
||||
catch (e) {
|
||||
logger.debug("ignoring bogus screen name: %o", hash)
|
||||
hash = null;
|
||||
}
|
||||
|
||||
var url = '/client#/home';
|
||||
|
||||
var $destination = $('[layout-id="' + screen + '"]');
|
||||
|
||||
if(!context.JK.currentUserId && !$destination.is('.no-login-required')) {
|
||||
logger.debug("not logged in so redirected to login from screen: " + screen)
|
||||
var redirectPath= '?redirect-to=' + encodeURIComponent(JK.locationPath());
|
||||
if(gon.isNativeClient) {
|
||||
window.location.href = '/signin' + redirectPath;
|
||||
}
|
||||
else {
|
||||
window.location.href = '/' + redirectPath;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var url = '/client#/' + screen;
|
||||
if (hash) {
|
||||
url = hash;
|
||||
}
|
||||
|
||||
logger.debug("Changing screen to " + url);
|
||||
logger.debug("jamkazam: Changing screen to " + url + " (hash=" + hash + ")") ;
|
||||
context.location = url;
|
||||
}
|
||||
|
||||
|
|
@ -377,7 +397,11 @@
|
|||
app.notify({title: "Unable to Load User", text: "You should reload the page."})
|
||||
});
|
||||
}
|
||||
} // if userDeferred
|
||||
}
|
||||
else {
|
||||
userDeferred = new $.Deferred();
|
||||
userDeferred.reject('not_logged_in');
|
||||
}
|
||||
|
||||
$(document).triggerHandler('JAMKAZAM_READY', {app:app})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,263 +0,0 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.JamTrackScreen = function(app) {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
|
||||
var $screen = null;
|
||||
var $content = null;
|
||||
var $scroller = null;
|
||||
var $genre = null;
|
||||
var $instrument = null;
|
||||
var $availability = null;
|
||||
var $nextPager = null;
|
||||
var $noMoreJamtracks = null;
|
||||
|
||||
var currentQuery = defaultQuery();
|
||||
var currentPage = 0;
|
||||
var LIMIT = 10;
|
||||
var next = null;
|
||||
var instrument_logo_map = context.JK.getInstrumentIconMap24();
|
||||
|
||||
function beforeShow(data) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function events() {
|
||||
$genre.on("change", search);
|
||||
$instrument.on("change", search);
|
||||
$availability.on("change", search);
|
||||
}
|
||||
|
||||
function clearResults() {
|
||||
//logger.debug("CLEARING CONTENT")
|
||||
currentPage = 0;
|
||||
$content.empty();
|
||||
$noMoreJamtracks.hide();
|
||||
next = null;
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
currentQuery = buildQuery();
|
||||
rest.getJamtracks(currentQuery)
|
||||
.done(function(response) {
|
||||
clearResults();
|
||||
handleJamtrackResponse(response);
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
clearResults();
|
||||
$noMoreJamtracks.show();
|
||||
app.notifyServerError(jqXHR, 'Jamtrack Unavailable')
|
||||
})
|
||||
}
|
||||
|
||||
function search() {
|
||||
logger.debug("Searching for jamtracks...");
|
||||
refresh();
|
||||
return false;
|
||||
}
|
||||
|
||||
function defaultQuery() {
|
||||
var query = { limit:LIMIT, page:currentPage};
|
||||
|
||||
if(next) {
|
||||
query.since = next;
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
function buildQuery() {
|
||||
currentQuery = defaultQuery();
|
||||
|
||||
// genre filter
|
||||
var genres = $screen.find('#jamtrack_genre').val();
|
||||
if (genres !== undefined) {
|
||||
currentQuery.genre = genres;
|
||||
}
|
||||
|
||||
// instrument filter
|
||||
var instrument = $instrument.val();
|
||||
if (instrument !== undefined) {
|
||||
currentQuery.instrument = instrument;
|
||||
}
|
||||
|
||||
// availability filter
|
||||
var availability = $availability.val();
|
||||
if (availability !== undefined) {
|
||||
currentQuery.availability = availability;
|
||||
}
|
||||
|
||||
return currentQuery;
|
||||
}
|
||||
|
||||
function handleJamtrackResponse(response) {
|
||||
//logger.debug("Handling response", JSON.stringify(response))
|
||||
next = response.next;
|
||||
|
||||
renderJamtracks(response);
|
||||
|
||||
if(response.next == null) {
|
||||
// if we less results than asked for, end searching
|
||||
$scroller.infinitescroll('pause');
|
||||
logger.debug("end of jamtracks");
|
||||
|
||||
if(currentPage == 0 && response.jamtracks.length == 0) {
|
||||
$content.append("<div class='no-jamtracks-msg'>There's no jamtracks.</div>") ;
|
||||
}
|
||||
|
||||
if(currentPage > 0) {
|
||||
$noMoreJamtracks.show();
|
||||
// there are bugs with infinitescroll not removing the 'loading'.
|
||||
// it's most noticeable at the end of the list, so whack all such entries
|
||||
$('.infinite-scroll-loader').remove();
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentPage++;
|
||||
buildQuery();
|
||||
registerInfiniteScroll();
|
||||
}
|
||||
}
|
||||
|
||||
function registerInfiniteScroll() {
|
||||
$scroller.infinitescroll({
|
||||
behavior: 'local',
|
||||
navSelector: '#jamtrackScreen .btn-next-pager',
|
||||
nextSelector: '#jamtrackScreen .btn-next-pager',
|
||||
binder: $scroller,
|
||||
dataType: 'json',
|
||||
appendCallback: false,
|
||||
prefill: false,
|
||||
bufferPx: 100,
|
||||
loading: {
|
||||
msg: $('<div class="infinite-scroll-loader">Loading ...</div>'),
|
||||
img: '/assets/shared/spinner.gif'
|
||||
},
|
||||
path: function(page) {
|
||||
return '/api/jamtracks?' + $.param(buildQuery());
|
||||
}
|
||||
},function(json, opts) {
|
||||
handleJamtrackResponse(json);
|
||||
});
|
||||
$scroller.infinitescroll('resume');
|
||||
}
|
||||
|
||||
function playJamtrack(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function addToCartJamtrack(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var params = {id: $(e.target).attr("data-jamtrack-id")};
|
||||
rest.addJamtrackToShoppingCart(params)
|
||||
.done(function(response) {
|
||||
context.location = "/client#/shoppingCart";
|
||||
})
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function licenseUSWhy(e) {
|
||||
e.preventDefault();
|
||||
|
||||
app.layout.showDialog('jamtrack-availability-dialog');
|
||||
}
|
||||
|
||||
function registerEvents() {
|
||||
$screen.find('.jamtrack-detail-btn').on("click", showJamtrackDescription);
|
||||
$screen.find('.play-button').on('click', playJamtrack);
|
||||
$screen.find('.jamtrack-add-cart').on('click', addToCartJamtrack);
|
||||
$screen.find('.license-us-why').on('click', licenseUSWhy);
|
||||
}
|
||||
|
||||
function renderJamtracks(data) {
|
||||
$.each(data.jamtracks, function(i, jamtrack) {
|
||||
$.each(jamtrack.tracks, function (index, track) {
|
||||
|
||||
if(track.track_type == 'Master') {
|
||||
return; // continue
|
||||
}
|
||||
|
||||
var inst = '../assets/content/icon_instrument_default24.png';
|
||||
if (track.instrument.id in instrument_logo_map) {
|
||||
inst = instrument_logo_map[track.instrument.id].asset;
|
||||
}
|
||||
track.instrument_url = inst;
|
||||
|
||||
track.instrument_desc = track.instrument.description;
|
||||
if (track.part != "") {
|
||||
track.instrument_desc += " ( " + track.part + " )";
|
||||
}
|
||||
});
|
||||
|
||||
var options = {
|
||||
jamtrack: jamtrack
|
||||
};
|
||||
|
||||
var $jamtrackItem = $(
|
||||
context._.template(
|
||||
$('#template-jamtrack').html(),
|
||||
options,
|
||||
{variable: 'data'}
|
||||
)
|
||||
);
|
||||
renderJamtrack($jamtrackItem );
|
||||
});
|
||||
|
||||
registerEvents();
|
||||
}
|
||||
|
||||
function showJamtrackDescription(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $description = $(e.target).parent(".detail-arrow").next();
|
||||
if ($description.css("display") == "none") {
|
||||
$description.show();
|
||||
}
|
||||
else {
|
||||
$description.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function renderJamtrack(jamtrack) {
|
||||
$content.append(jamtrack);
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
app.bindScreen('jamtrack', screenBindings);
|
||||
|
||||
$screen = $("#jamtrack-find-form");
|
||||
$scroller = $screen.find('.content-body-scroller');
|
||||
$content = $screen.find(".jamtrack-content");
|
||||
$genre = $screen.find("#jamtrack_genre");
|
||||
$instrument = $screen.find("#jamtrack_instrument");
|
||||
$availability = $screen.find("#jamtrack_availability");
|
||||
$nextPager = $screen.find("a.btn-next-pager");
|
||||
$noMoreJamtracks = $screen.find("#end-of-jamtrack-list");
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
if($scroller.length == 0) throw "$scroller must be specified";
|
||||
if($content.length == 0) throw "$content must be specified";
|
||||
if($noMoreJamtracks.length == 0) throw "$noMoreJamtracks must be specified";
|
||||
if($genre.length == 0) throw "$genre must be specified";
|
||||
if($instrument.length == 0) throw "$instrument must be specified";
|
||||
if($availability.length ==0) throw "$availability must be specified";
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {}
|
||||
|
||||
context.JK.JamTrackScreen=class JamTrackScreen
|
||||
LIMIT = 10
|
||||
instrument_logo_map = context.JK.getInstrumentIconMap24()
|
||||
|
||||
constructor: (@app) ->
|
||||
@logger = context.JK.logger
|
||||
@screen = null
|
||||
@content = null
|
||||
@scroller = null
|
||||
@genre = null
|
||||
@artist = null
|
||||
@instrument = null
|
||||
@availability = null
|
||||
@nextPager = null
|
||||
@noMoreJamtracks = null
|
||||
@currentPage = 0
|
||||
@next = null
|
||||
@currentQuery = this.defaultQuery()
|
||||
@expanded = false
|
||||
|
||||
beforeShow:(data) =>
|
||||
this.setFilterFromURL()
|
||||
this.refresh()
|
||||
|
||||
afterShow:(data) =>
|
||||
|
||||
events:() =>
|
||||
@genre.on 'change', this.search
|
||||
@artist.on 'change', this.search
|
||||
@instrument.on 'change', this.search
|
||||
@availability.on 'change', this.search
|
||||
|
||||
clearResults:() =>
|
||||
#$logger.debug("CLEARING CONTENT")
|
||||
@currentPage = 0
|
||||
@content.empty()
|
||||
@noMoreJamtracks.hide()
|
||||
@next = null
|
||||
|
||||
setFilterFromURL:() =>
|
||||
# Grab parms from URL for artist, instrument, and availability
|
||||
parms=this.getParams()
|
||||
this.logger.debug("parms", parms)
|
||||
if(parms.artist?)
|
||||
@artist.val(parms.artist)
|
||||
if(parms.instrument?)
|
||||
@instrument.val(parms.instrument)
|
||||
if(parms.availability?)
|
||||
@availability.val(parms.availability)
|
||||
window.history.replaceState({}, "", "/client#/jamtrack")
|
||||
|
||||
getParams:() =>
|
||||
params = {}
|
||||
q = window.location.href.split("?")[1]
|
||||
if q?
|
||||
q = q.split('#')[0]
|
||||
raw_vars = q.split("&")
|
||||
for v in raw_vars
|
||||
[key, val] = v.split("=")
|
||||
params[key] = decodeURIComponent(val)
|
||||
params
|
||||
|
||||
refresh:() =>
|
||||
@currentQuery = this.buildQuery()
|
||||
that = this
|
||||
rest.getJamtracks(@currentQuery).done((response) ->
|
||||
that.clearResults()
|
||||
that.handleJamtrackResponse(response)
|
||||
).fail (jqXHR) ->
|
||||
that.clearResults()
|
||||
that.noMoreJamtracks.show()
|
||||
that.app.notifyServerError jqXHR, 'Jamtrack Unavailable'
|
||||
|
||||
search:() =>
|
||||
this.refresh()
|
||||
false
|
||||
|
||||
defaultQuery:() =>
|
||||
query =
|
||||
per_page: LIMIT
|
||||
page: @currentPage+1
|
||||
if @next
|
||||
query.since = @next
|
||||
query
|
||||
|
||||
buildQuery:() =>
|
||||
@currentQuery = this.defaultQuery()
|
||||
# genre filter
|
||||
# var genres = @screen.find('#jamtrack_genre').val()
|
||||
# if (genres !== undefined) {
|
||||
# @currentQuery.genre = genres
|
||||
# }
|
||||
# instrument filter
|
||||
|
||||
instrument = @instrument.val()
|
||||
if instrument?
|
||||
@currentQuery.instrument = instrument
|
||||
|
||||
# artist filter
|
||||
art = @artist.val()
|
||||
if art?
|
||||
@currentQuery.artist = art
|
||||
|
||||
# availability filter
|
||||
availability = @availability.val()
|
||||
if availability?
|
||||
@currentQuery.availability = availability
|
||||
@currentQuery
|
||||
|
||||
handleJamtrackResponse:(response) =>
|
||||
#logger.debug("Handling response", JSON.stringify(response))
|
||||
@next = response.next
|
||||
this.renderJamtracks(response)
|
||||
if response.next == null
|
||||
# if we less results than asked for, end searching
|
||||
@scroller.infinitescroll 'pause'
|
||||
if @currentPage == 0 and response.jamtracks.length == 0
|
||||
@content.append '<div class=\'no-jamtracks-msg\'>There\'s no jamtracks.</div>'
|
||||
if @currentPage > 0
|
||||
@noMoreJamtracks.show()
|
||||
# there are bugs with infinitescroll not removing the 'loading'.
|
||||
# it's most noticeable at the end of the list, so whack all such entries
|
||||
$('.infinite-scroll-loader').remove()
|
||||
else
|
||||
@currentPage++
|
||||
this.buildQuery()
|
||||
this.registerInfiniteScroll()
|
||||
|
||||
|
||||
registerInfiniteScroll:() =>
|
||||
@scroller.infinitescroll {
|
||||
behavior: 'local'
|
||||
navSelector: '#jamtrackScreen .btn-next-pager'
|
||||
nextSelector: '#jamtrackScreen .btn-next-pager'
|
||||
binder: @scroller
|
||||
dataType: 'json'
|
||||
appendCallback: false
|
||||
prefill: false
|
||||
bufferPx: 100
|
||||
loading:
|
||||
msg: $('<div class="infinite-scroll-loader">Loading ...</div>')
|
||||
img: '/assets/shared/spinner.gif'
|
||||
path: (page) ->
|
||||
'/api/jamtracks?' + $.param(this.buildQuery())
|
||||
|
||||
}, (json, opts) ->
|
||||
this.handleJamtrackResponse(json)
|
||||
@scroller.infinitescroll 'resume'
|
||||
|
||||
playJamtrack:(e) =>
|
||||
e.preventDefault()
|
||||
|
||||
addToCartJamtrack:(e) =>
|
||||
e.preventDefault()
|
||||
params = id: $(e.target).attr('data-jamtrack-id')
|
||||
rest.addJamtrackToShoppingCart(params).done((response) ->
|
||||
context.location = '/client#/shoppingCart'
|
||||
).fail @app.ajaxError
|
||||
|
||||
licenseUSWhy:(e) =>
|
||||
e.preventDefault()
|
||||
@app.layout.showDialog 'jamtrack-availability-dialog'
|
||||
|
||||
registerEvents:() =>
|
||||
@screen.find('.jamtrack-detail-btn').on 'click', this.showJamtrackDescription
|
||||
@screen.find('.play-button').on 'click', this.playJamtrack
|
||||
@screen.find('.jamtrack-add-cart').on 'click', this.addToCartJamtrack
|
||||
@screen.find('.license-us-why').on 'click', this.licenseUSWhy
|
||||
@screen.find('.jamtrack-detail-btn').on 'click', this.toggleExpanded
|
||||
|
||||
renderJamtracks:(data) =>
|
||||
that = this
|
||||
for jamtrack in data.jamtracks
|
||||
for track in jamtrack.tracks
|
||||
continue if track.track_type=='Master'
|
||||
inst = '../assets/content/icon_instrument_default24.png'
|
||||
if track.instrument.id in instrument_logo_map
|
||||
inst = instrument_logo_map[track.instrument.id].asset
|
||||
track.instrument_url = inst
|
||||
track.instrument_desc = track.instrument.description
|
||||
if track.part != ''
|
||||
track.instrument_desc += ' (' + track.part + ')'
|
||||
|
||||
options =
|
||||
jamtrack: jamtrack
|
||||
expanded: that.expanded
|
||||
|
||||
@jamtrackItem = $(context._.template($('#template-jamtrack').html(), options, variable: 'data'))
|
||||
that.renderJamtrack(@jamtrackItem)
|
||||
this.registerEvents()
|
||||
|
||||
showJamtrackDescription:(e) =>
|
||||
e.preventDefault()
|
||||
@description = $(e.target).parent('.detail-arrow').next()
|
||||
if @description.css('display') == 'none'
|
||||
@description.show()
|
||||
else
|
||||
@description.hide()
|
||||
|
||||
toggleExpanded:() =>
|
||||
this.expanded = !this.expanded
|
||||
this.refresh()
|
||||
|
||||
renderJamtrack:(jamtrack) =>
|
||||
@content.append jamtrack
|
||||
|
||||
initialize:() =>
|
||||
screenBindings =
|
||||
'beforeShow': this.beforeShow
|
||||
'afterShow': this.afterShow
|
||||
@app.bindScreen 'jamtrack', screenBindings
|
||||
@screen = $('#jamtrack-find-form')
|
||||
@scroller = @screen.find('.content-body-scroller')
|
||||
@content = @screen.find('.jamtrack-content')
|
||||
@genre = @screen.find('#jamtrack_genre')
|
||||
@artist = @screen.find('#jamtrack_artist')
|
||||
@instrument = @screen.find('#jamtrack_instrument')
|
||||
@availability = @screen.find('#jamtrack_availability')
|
||||
@nextPager = @screen.find('a.btn-next-pager')
|
||||
@noMoreJamtracks = @screen.find('.end-of-jamtrack-list')
|
||||
if @screen.length == 0
|
||||
throw new Error('@screen must be specified')
|
||||
if @scroller.length == 0
|
||||
throw new Error('@scroller must be specified')
|
||||
if @content.length == 0
|
||||
throw new Error('@content must be specified')
|
||||
if @noMoreJamtracks.length == 0
|
||||
throw new Error('@noMoreJamtracks must be specified')
|
||||
#if(@genre.length == 0) throw new Error("@genre must be specified")
|
||||
|
||||
if @artist.length == 0
|
||||
throw new Error('@artist must be specified')
|
||||
if @instrument.length == 0
|
||||
throw new Error('@instrument must be specified')
|
||||
if @availability.length == 0
|
||||
throw new Error('@availability must be specified')
|
||||
this.events()
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {}
|
||||
|
||||
context.JK.JamTrackLanding = class JamTrackLanding
|
||||
constructor: (@app) ->
|
||||
@rest = context.JK.Rest()
|
||||
@client = context.jamClient
|
||||
@logger = context.JK.logger
|
||||
@screen = null
|
||||
|
||||
initialize:() =>
|
||||
screenBindings =
|
||||
'beforeShow': @beforeShow
|
||||
'afterShow': @afterShow
|
||||
@app.bindScreen('jamtrackLanding', screenBindings)
|
||||
@screen = $('#jamtrackLanding')
|
||||
|
||||
beforeShow:() =>
|
||||
# Get artist names and build links
|
||||
@rest.getJamtracks({group_artist: true})
|
||||
.done(this.buildArtistLinks)
|
||||
.fail(this.handleFailure)
|
||||
|
||||
# Bind links to action that will open the jam_tracks list view filtered to given artist_name:
|
||||
# artist_name
|
||||
this.bindArtistLinks()
|
||||
afterShow:() =>
|
||||
|
||||
buildArtistLinks:(response) =>
|
||||
# Get artist names and build links
|
||||
jamtracks = response.jamtracks
|
||||
$("#band_list>li:not('#no_bands_found')").remove()
|
||||
if jamtracks.length==0
|
||||
$("#no_bands_found").removeClass("hidden")
|
||||
else
|
||||
$("#no_bands_found").addClass("hidden")
|
||||
|
||||
# client#/jamtrack
|
||||
for jamtrack in jamtracks
|
||||
artistLink = "<a href='client?artist=#{encodeURIComponent(jamtrack.original_artist)}#/jamtrack' class='artist-link' artist='#{jamtrack.original_artist}'>#{jamtrack.original_artist}</a>"
|
||||
$("#band_list").append("<li>#{artistLink}</li>")
|
||||
|
||||
# We don't want to do a full page load if this is clicked on here:
|
||||
bindArtistLinks:() =>
|
||||
band_list=$("ul#band_list")
|
||||
that=this
|
||||
band_list.on "click", "a.artist-link", (event)->
|
||||
context.location="client#/jamtrack"
|
||||
window.history.replaceState({}, "", this.href)
|
||||
event.preventDefault()
|
||||
|
||||
handleFailure:(error) =>
|
||||
|
|
@ -95,6 +95,8 @@
|
|||
layoutHeader(width, height);
|
||||
layoutNotify(width, height);
|
||||
layoutFooter(width, height);
|
||||
|
||||
$(document).triggerHandler('layout_resized');
|
||||
}
|
||||
|
||||
function layoutCurtain(screenWidth, screenHeight) {
|
||||
|
|
@ -407,8 +409,15 @@
|
|||
}
|
||||
|
||||
var destination = $(evt.currentTarget).attr('layout-link');
|
||||
var destinationType = $('[layout-id="' + destination + '"]').attr("layout");
|
||||
var $destination = $('[layout-id="' + destination + '"]');
|
||||
|
||||
var destinationType = $destination.attr("layout");
|
||||
if (destinationType === "screen") {
|
||||
if(!context.JK.currentUserId && !$destination.is('.no-login-required')) {
|
||||
// there is no user, and this item does not support 'no-login', so warn user
|
||||
showDialog('login-required-dialog');
|
||||
return;
|
||||
}
|
||||
context.location = '/client#/' + destination;
|
||||
} else if (destinationType === "dialog") {
|
||||
showDialog(destination);
|
||||
|
|
@ -540,7 +549,7 @@
|
|||
var accepted = screenEvent(previousScreen, 'beforeHide', data);
|
||||
if(accepted === false) return;
|
||||
|
||||
logger.debug("Changing screen to " + currentScreen);
|
||||
logger.debug("layout: changing screen to " + currentScreen);
|
||||
|
||||
$(document).triggerHandler(EVENTS.SCREEN_CHANGED, {previousScreen: previousScreen, newScreen: currentScreen})
|
||||
|
||||
|
|
@ -687,6 +696,7 @@
|
|||
return null;
|
||||
}
|
||||
logger.debug("opening dialog: " + dialog)
|
||||
|
||||
var $overlay = $('.dialog-overlay')
|
||||
|
||||
if (opts.sizeOverlayToContent) {
|
||||
|
|
@ -719,6 +729,12 @@
|
|||
|
||||
function panelHeaderClicked(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
if(!context.JK.currentUserId) {
|
||||
showDialog('login-required-dialog');
|
||||
return false;
|
||||
}
|
||||
|
||||
expandedPanel = $(evt.currentTarget).closest('[layout="panel"]').attr("layout-id");
|
||||
layout();
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@
|
|||
})
|
||||
.fail(function() {
|
||||
isLoading = false;
|
||||
app.ajaxError();
|
||||
app.ajaxError(arguments);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1375,7 +1375,9 @@
|
|||
|
||||
events();
|
||||
|
||||
populate();
|
||||
app.user().done(function(){
|
||||
populate();
|
||||
})
|
||||
};
|
||||
|
||||
this.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
step = 2;
|
||||
renderNavigation();
|
||||
renderAccountInfo();
|
||||
$("#order_error").addClass("hidden")
|
||||
}
|
||||
|
||||
function resetJamTrackDownloadInfo() {
|
||||
|
|
@ -115,6 +116,7 @@
|
|||
purchasedJamTrackIterator = 0;
|
||||
}
|
||||
|
||||
// TODO: Refactor: this function is long and fraught with many return points.
|
||||
function next(e) {
|
||||
e.preventDefault();
|
||||
$("#order_error").addClass("hidden")
|
||||
|
|
@ -308,10 +310,8 @@
|
|||
$paymentMethod.find('#divCardName .error-text').remove();
|
||||
$paymentMethod.find('#divCardName').addClass("error");
|
||||
$paymentMethod.find('#card-name').after("<ul class='error-text'><li>Card Name is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$paymentMethod.find('#divCardName').removeClass("error");
|
||||
}
|
||||
|
||||
|
|
@ -319,21 +319,37 @@
|
|||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>Card Number is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
} else if (!$.payment.validateCardNumber(card_number)) {
|
||||
$paymentMethod.find('#divCardNumber .error-text').remove();
|
||||
$paymentMethod.find('#divCardNumber').addClass("error");
|
||||
$paymentMethod.find('#card-number').after("<ul class='error-text'><li>Card Number is not valid</li></ul>");
|
||||
return false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardNumber').removeClass("error");
|
||||
}
|
||||
|
||||
if (!$.payment.validateCardExpiry(card_month, card_year)) {
|
||||
$paymentMethod.find('#divCardExpiry .error-text').remove();
|
||||
$paymentMethod.find('#divCardExpiry').addClass("error");
|
||||
$paymentMethod.find('#card-expiry').after("<ul class='error-text'><li>Card Number is not valid</li></ul>");
|
||||
} else {
|
||||
$paymentMethod.find('#divCardExpiry').removeClass("error");
|
||||
}
|
||||
|
||||
if (!card_verify) {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card_verify').after("<ul class='error-text'><li>Card Verification Value is required</li></ul>");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>Card Verification Value is required</li></ul>");
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
} else if(!$.payment.validateCardCVC(card_verify)) {
|
||||
$paymentMethod.find('#divCardVerify .error-text').remove();
|
||||
$paymentMethod.find('#divCardVerify').addClass("error");
|
||||
$paymentMethod.find('#card-verify').after("<ul class='error-text'><li>Card Verification Value is not valid.</li></ul>");
|
||||
|
||||
return false;
|
||||
} else {
|
||||
$paymentMethod.find('#divCardVerify').removeClass("error");
|
||||
}
|
||||
|
||||
|
|
@ -607,6 +623,10 @@
|
|||
radioClass: 'iradio_minimal',
|
||||
inheritClass: true
|
||||
});
|
||||
|
||||
// Use jquery.payment to limit characters and length:
|
||||
$paymentMethod.find("#card-number").payment('formatCardNumber');
|
||||
$paymentMethod.find("#card-verify").payment('formatCardCVC');
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
|
|
|||
|
|
@ -104,10 +104,10 @@
|
|||
|
||||
$playButton.on('click', function(e) {
|
||||
var sessionModel = context.JK.CurrentSessionModel || null;
|
||||
if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') {
|
||||
context.JK.prodBubble($fader, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $playButton})
|
||||
return false;
|
||||
}
|
||||
//if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') {
|
||||
// context.JK.prodBubble($fader, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $playButton})
|
||||
// return false;
|
||||
//}
|
||||
|
||||
startPlay();
|
||||
return false;
|
||||
|
|
@ -115,10 +115,10 @@
|
|||
|
||||
$pauseButton.on('click', function(e) {
|
||||
var sessionModel = context.JK.CurrentSessionModel || null;
|
||||
if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') {
|
||||
context.JK.prodBubble($pauseButton, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $pauseButton})
|
||||
return false;
|
||||
}
|
||||
//if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') {
|
||||
// context.JK.prodBubble($pauseButton, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $pauseButton})
|
||||
// return false;
|
||||
//}
|
||||
|
||||
stopPlay();
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1054,7 +1054,7 @@
|
|||
|
||||
context.JK.GenreSelectorHelper.render('#create-session-genre');
|
||||
|
||||
inviteMusiciansUtil.loadFriends();
|
||||
//inviteMusiciansUtil.loadFriends();
|
||||
|
||||
context.JK.dropdown($screen.find('#session-musician-access'));
|
||||
context.JK.dropdown($screen.find('#session-fans-access'));
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
context.JK.SelectLocation = Class.extend({
|
||||
|
||||
init: function ($countries, $regions, $cities, app) {
|
||||
init: function ($countries, $regions, $cities, app, useEasyDropdown) {
|
||||
this.api = context.JK.Rest();
|
||||
this.logger = context.JK.logger;
|
||||
this.loadingCitiesData = false;
|
||||
|
|
@ -14,9 +14,12 @@
|
|||
this.loadingCountriesData = false;
|
||||
this.nilOptionStr = '<option value=""></option>';
|
||||
this.nilOptionText = 'n/a';
|
||||
this.countriesLoaded = false;
|
||||
this.$countries = $countries;
|
||||
this.$regions = $regions;
|
||||
this.$cities = $cities;
|
||||
this.$deferred = null;
|
||||
this.useEasyDropdown = useEasyDropdown === undefined ? true : useEasyDropdown;
|
||||
this.app = app;
|
||||
|
||||
$countries.on('change', function (evt) {
|
||||
|
|
@ -24,11 +27,24 @@
|
|||
this.handleCountryChanged();
|
||||
return false;
|
||||
}.bind(this));
|
||||
$regions.on('change', function (evt) {
|
||||
evt.stopPropagation();
|
||||
this.handleRegionChanged();
|
||||
return false;
|
||||
}.bind(this));
|
||||
if($regions) {
|
||||
$regions.on('change', function (evt) {
|
||||
evt.stopPropagation();
|
||||
this.handleRegionChanged();
|
||||
return false;
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
selectCountry: function (country) {
|
||||
if(this.useEasyDropdown) {
|
||||
this.$countries.easyDropDown('select', country, true)
|
||||
}
|
||||
else {
|
||||
this.$countries.val(country)
|
||||
}
|
||||
},
|
||||
ready: function() {
|
||||
return this.$deferred;
|
||||
},
|
||||
load: function (country, region, city) {
|
||||
|
||||
|
|
@ -42,13 +58,9 @@
|
|||
country = 'US';
|
||||
}
|
||||
|
||||
this.loadingCountriesData = true;
|
||||
this.loadingRegionsData = true;
|
||||
this.loadingCitiesData = true;
|
||||
|
||||
// make the 3 slower requests, which only matter if the user wants to affect their ISP or location
|
||||
|
||||
this.api.getCountries()
|
||||
this.loadingCountriesData = true;
|
||||
this.$deferred = this.api.getCountries()
|
||||
.done(function (countriesx) {
|
||||
this.populateCountriesx(countriesx["countriesx"], country);
|
||||
}.bind(this))
|
||||
|
|
@ -57,7 +69,9 @@
|
|||
this.loadingCountriesData = false;
|
||||
}.bind(this))
|
||||
|
||||
if (country) {
|
||||
|
||||
if (country && this.$regions) {
|
||||
this.loadingRegionsData = true;
|
||||
this.api.getRegions({ country: country })
|
||||
.done(function (regions) {
|
||||
this.populateRegions(regions["regions"], region);
|
||||
|
|
@ -67,7 +81,8 @@
|
|||
this.loadingRegionsData = false;
|
||||
}.bind(this))
|
||||
|
||||
if (region) {
|
||||
if (region && this.$cities) {
|
||||
this.loadingCitiesData = true;
|
||||
this.api.getCities({ country: country, region: region })
|
||||
.done(function (cities) {
|
||||
this.populateCities(cities["cities"], this.city)
|
||||
|
|
@ -78,9 +93,15 @@
|
|||
}.bind(this))
|
||||
}
|
||||
}
|
||||
return this.$deferred;
|
||||
},
|
||||
handleCountryChanged: function () {
|
||||
var selectedCountry = this.$countries.val()
|
||||
|
||||
if(!this.$regions) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedRegion = this.$regions.val()
|
||||
var cityElement = this.$cities
|
||||
|
||||
|
|
@ -144,7 +165,9 @@
|
|||
else {
|
||||
cityElement.children().remove();
|
||||
cityElement.append($(this.nilOptionStr).text(this.nilOptionText));
|
||||
context.JK.dropdown(cityElement);
|
||||
if(this.useEasyDropdown) {
|
||||
context.JK.dropdown(cityElement);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -159,7 +182,7 @@
|
|||
if (!countryx.countrycode) return;
|
||||
|
||||
var option = $(this.nilOptionStr);
|
||||
option.text(countryx.countryname);
|
||||
option.text(countryx.countryname ? countryx.countryname : countryx.countrycode);
|
||||
option.attr("value", countryx.countrycode);
|
||||
|
||||
if (countryx.countrycode == this.country) {
|
||||
|
|
@ -170,6 +193,8 @@
|
|||
},
|
||||
populateCountriesx: function (countriesx) {
|
||||
|
||||
this.countriesLoaded = true;
|
||||
|
||||
// countriesx has the format [{countrycode: "US", countryname: "United States"}, ...]
|
||||
|
||||
this.foundCountry = false;
|
||||
|
|
@ -194,8 +219,9 @@
|
|||
|
||||
this.$countries.val(this.country);
|
||||
this.$countries.attr("disabled", null).easyDropDown('enable');
|
||||
|
||||
context.JK.dropdown(this.$countries);
|
||||
if(this.useEasyDropdown) {
|
||||
context.JK.dropdown(this.$countries);
|
||||
}
|
||||
},
|
||||
|
||||
writeRegion: function (index, region) {
|
||||
|
|
@ -220,7 +246,9 @@
|
|||
this.$regions.val(userRegion)
|
||||
this.$regions.attr("disabled", null).easyDropDown('enable');
|
||||
|
||||
context.JK.dropdown(this.$regions);
|
||||
if(this.useEasyDropdown) {
|
||||
context.JK.dropdown(this.$regions);
|
||||
}
|
||||
},
|
||||
|
||||
writeCity: function (index, city) {
|
||||
|
|
@ -245,7 +273,9 @@
|
|||
this.$cities.val(userCity)
|
||||
this.$cities.attr("disabled", null).easyDropDown('enable');
|
||||
|
||||
context.JK.dropdown(this.$cities);
|
||||
if(this.useEasyDropdown) {
|
||||
context.JK.dropdown(this.$cities);
|
||||
}
|
||||
},
|
||||
|
||||
regionListFailure: function (jqXHR, textStatus, errorThrown) {
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@
|
|||
var claimedRecording = null;
|
||||
var backing_track_path = null;
|
||||
var jamTrack = null;
|
||||
|
||||
var metronomeMixer = null;
|
||||
var playbackControls = null;
|
||||
var promptLeave = false;
|
||||
|
|
@ -115,6 +116,11 @@
|
|||
var $metronomePlaybackSelect = null;
|
||||
var $metronomePlaybackHelp = null;
|
||||
var $templatePendingMetronome = null;
|
||||
var $myTracks = null;
|
||||
var $liveTracks = null;
|
||||
var $audioTracks = null;
|
||||
var $fluidTracks = null;
|
||||
|
||||
var mediaTrackGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup];
|
||||
var muteBothMasterAndPersonalGroups = [ChannelGroupIds.AudioInputMusicGroup, ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup];
|
||||
|
||||
|
|
@ -480,6 +486,12 @@
|
|||
function checkMetronomeTransition() {
|
||||
// trust backend over server
|
||||
|
||||
if(sessionModel.jamTracks() !== null || sessionModel.recordedJamTracks() !== null) {
|
||||
// ignore all metronome events when jamtracks are open, because backend opens metronome mixer to play jamtrack tap-ins
|
||||
logger.debug("ignore checkMetronomeTransition because JamTrack is open")
|
||||
return;
|
||||
}
|
||||
|
||||
var metronomeMasterMixers = getMetronomeMasterMixers();
|
||||
|
||||
if (metronomeMixer == null && metronomeMasterMixers.length > 0) {
|
||||
|
|
@ -513,6 +525,7 @@
|
|||
backing_track_path = currentSession == null ? null : currentSession.backing_track_path;
|
||||
}
|
||||
|
||||
|
||||
function checkRecordingTransition(currentSession) {
|
||||
// handle claimed recordings
|
||||
if (claimedRecording == null && (currentSession && currentSession.claimed_recording != null)) {
|
||||
|
|
@ -604,6 +617,8 @@
|
|||
$('.session-recordings .recording-controls').hide();
|
||||
$closePlaybackRecording.show();
|
||||
$('.session-recordings .session-recording-name').text('(No audio loaded)')
|
||||
$('.session-recordings').attr('media-state', 'closed')
|
||||
$('.session-livetracks').attr('media-state', 'closed')
|
||||
}
|
||||
}
|
||||
function didSelfOpenMedia() {
|
||||
|
|
@ -635,7 +650,7 @@
|
|||
}
|
||||
checkPendingMetronome();
|
||||
resetOtherAudioContent();
|
||||
|
||||
resizeFluid();
|
||||
/**
|
||||
if ($('.session-recordings .track').length === 0) {
|
||||
$('.session-recordings .when-empty').show();
|
||||
|
|
@ -947,6 +962,11 @@
|
|||
|
||||
var recordedBackingTracks = sessionModel.recordedBackingTracks();
|
||||
var backingTracks = sessionModel.backingTracks();
|
||||
var recordedJamTracks = sessionModel.recordedJamTracks();
|
||||
var jamTracks = sessionModel.jamTracks();
|
||||
|
||||
//logger.debug("localMediaMixers", localMediaMixers)
|
||||
//logger.debug("peerMediaMixers", peerLocalMediaMixers)
|
||||
|
||||
// with mixer info, we use these to decide what kind of tracks are open in the backend
|
||||
|
||||
|
|
@ -981,29 +1001,57 @@
|
|||
// additional check; if we can match an id in backing tracks or recorded backing track,
|
||||
// we need to remove it from the recorded track set, but move it to the backing track set
|
||||
|
||||
var isBackingTrack = false
|
||||
if(recordedBackingTracks) {
|
||||
context._.each(recordedBackingTracks, function (recordedBackingTrack) {
|
||||
if (mixer.id == 'L' + recordedBackingTrack.client_track_id) {
|
||||
isBackingTrack = true;
|
||||
return false; // break
|
||||
}
|
||||
})
|
||||
}
|
||||
if(backingTracks) {
|
||||
context._.each(backingTracks, function (backingTrack) {
|
||||
if (mixer.id == 'L' + backingTrack.client_track_id) {
|
||||
isBackingTrack = true;
|
||||
var isJamTrack = false;
|
||||
|
||||
if(jamTracks) {
|
||||
// check if the ID matches that of an open jam track
|
||||
context._.each(jamTracks, function (jamTrack) {
|
||||
if (mixer.id == jamTrack.id) {
|
||||
isJamTrack = true;
|
||||
return false; // break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(isBackingTrack) {
|
||||
backingTrackMixers.push(mixer)
|
||||
if(!isJamTrack && recordedJamTracks) {
|
||||
// then check if the ID matches that of a open, recorded jam track
|
||||
context._.each(recordedJamTracks, function (recordedJamTrack) {
|
||||
if (mixer.id == recordedJamTrack.id) {
|
||||
isJamTrack = true;
|
||||
return false; // break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(isJamTrack) {
|
||||
jamTrackMixers.push(mixer)
|
||||
}
|
||||
else {
|
||||
recordingTrackMixers.push(mixer);
|
||||
var isBackingTrack = false
|
||||
if (recordedBackingTracks) {
|
||||
context._.each(recordedBackingTracks, function (recordedBackingTrack) {
|
||||
if (mixer.id == 'L' + recordedBackingTrack.client_track_id) {
|
||||
isBackingTrack = true;
|
||||
return false; // break
|
||||
}
|
||||
})
|
||||
}
|
||||
if (backingTracks) {
|
||||
context._.each(backingTracks, function (backingTrack) {
|
||||
if (mixer.id == 'L' + backingTrack.client_track_id) {
|
||||
isBackingTrack = true;
|
||||
return false; // break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (isBackingTrack) {
|
||||
backingTrackMixers.push(mixer)
|
||||
}
|
||||
else {
|
||||
// couldn't resolve this as a JamTrack or Backing track, must be a normal recorded file
|
||||
recordingTrackMixers.push(mixer);
|
||||
}
|
||||
}
|
||||
} else if(mediaType == 'PeerMediaTrack' || mediaType == 'BackingTrack') {
|
||||
// BackingTrack
|
||||
|
|
@ -1033,7 +1081,7 @@
|
|||
if(jamTrackMixers.length > 0) {
|
||||
renderJamTracks(jamTrackMixers);
|
||||
}
|
||||
if(metronomeTrackMixers.length > 0) {
|
||||
if(metronomeTrackMixers.length > 0 && sessionModel.jamTracks() === null && sessionModel.recordedJamTracks() == null) {
|
||||
renderMetronomeTracks(metronomeTrackMixers);
|
||||
}
|
||||
if(adhocTrackMixers.length > 0) {
|
||||
|
|
@ -1170,7 +1218,20 @@
|
|||
|
||||
function renderJamTracks(jamTrackMixers) {
|
||||
logger.debug("rendering jam tracks")
|
||||
var jamTracks = sessionModel.jamTracks();
|
||||
|
||||
var jamTracks = []
|
||||
var jamTrackName = 'JamTrack';
|
||||
if(sessionModel.isPlayingRecording()) {
|
||||
// only return managed mixers for recorded backing tracks
|
||||
jamTracks = sessionModel.recordedJamTracks();
|
||||
jamTrackName = sessionModel.recordedJamTrackName();
|
||||
}
|
||||
else {
|
||||
// only return un-managed (ad-hoc) mixers for normal backing tracks
|
||||
jamTracks = sessionModel.jamTracks();
|
||||
jamTrackName = sessionModel.jamTrackName();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between JamTrack vs Peer)
|
||||
|
|
@ -1179,7 +1240,7 @@
|
|||
|
||||
// using the server's info in conjuction with the client's, draw the recording tracks
|
||||
if(jamTracks) {
|
||||
$('.session-recording-name').text(sessionModel.getCurrentSession().jam_track.name);
|
||||
$('.session-recording-name').text(jamTrackName);
|
||||
|
||||
var noCorrespondingTracks = false;
|
||||
$.each(jamTrackMixers, function(index, mixer) {
|
||||
|
|
@ -1870,6 +1931,39 @@
|
|||
function otherAudioFilled() {
|
||||
$('.session-recordings .when-empty').hide();
|
||||
$('.session-recording-name-wrapper').show();
|
||||
$('.session-recordings').attr('media-state', 'open');
|
||||
$('.session-livetracks').attr('media-state', 'open');
|
||||
}
|
||||
|
||||
|
||||
function resizeFluid() {
|
||||
var trackWidth = 78; // 70 width + 8 margin
|
||||
var trackPadding = 30; // 15px left and right
|
||||
|
||||
var numLiveTracks = $liveTracks.find('.track').length;
|
||||
var numAudioTracks = $audioTracks.find('.track').length;
|
||||
var totalWidth = $fluidTracks.width();
|
||||
|
||||
|
||||
// calculate desired audio tracks width
|
||||
var minimumLiveTrackWidth = numLiveTracks * trackWidth + trackPadding;
|
||||
var otherAudioWidth = numAudioTracks * trackWidth + trackPadding;
|
||||
var liveTrackWidth = totalWidth - otherAudioWidth;
|
||||
|
||||
// live tracks get precedence over audio tracks, if there is a content over width usage
|
||||
if(liveTrackWidth < minimumLiveTrackWidth) {
|
||||
logger.debug("live track width trumping mode")
|
||||
liveTrackWidth = minimumLiveTrackWidth;
|
||||
otherAudioWidth = totalWidth - liveTrackWidth;
|
||||
}
|
||||
|
||||
var otherAudioWidthPct = Math.floor(100 * otherAudioWidth/totalWidth);
|
||||
var liveTrackWidthPct = Math.ceil(100 * liveTrackWidth/totalWidth);
|
||||
|
||||
logger.debug("resizeFluid: ", minimumLiveTrackWidth, otherAudioWidth, otherAudioWidthPct, liveTrackWidthPct, liveTrackWidthPct)
|
||||
|
||||
$audioTracks.css('width', otherAudioWidthPct + '%');
|
||||
$liveTracks.css('width', liveTrackWidthPct + '%');
|
||||
}
|
||||
|
||||
function _addRecordingTrack(trackData, mixer, oppositeMixer) {
|
||||
|
|
@ -2169,6 +2263,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$.each(mixerIds, function(i,v) {
|
||||
var mixerId = v;
|
||||
// behavior: if this is the user's track in personal mode, then we mute the track globally
|
||||
|
|
@ -2553,6 +2649,8 @@
|
|||
{ title: "JamTrack Can Not Open",
|
||||
text: "Unable to open your JamTrack. Please contact support@jamkazam.com"
|
||||
}, null, true);
|
||||
} else {
|
||||
rest.playJamTrack(jamTrack.id);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -2806,20 +2904,32 @@
|
|||
}
|
||||
|
||||
function onChangePlayPosition(e, data){
|
||||
logger.debug("calling jamClient.SessionTrackSeekMs(" + data.positionMs + ")");
|
||||
|
||||
var seek = data.positionMs;
|
||||
|
||||
if(data.playbackMonitorMode == context.JK.PLAYBACK_MONITOR_MODE.JAMTRACK) {
|
||||
context.jamClient.SessionJamTrackSeekMs(data.positionMs);
|
||||
// if positionMs == 0, then seek it back to whatever the earliest play start is to catch all the prelude
|
||||
|
||||
if(seek == 0) {
|
||||
var duration = context.jamClient.SessionGetJamTracksPlayDurationMs();
|
||||
seek = duration.start;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("calling jamClient.SessionTrackSeekMs(" + seek + ")");
|
||||
|
||||
if(data.playbackMonitorMode == context.JK.PLAYBACK_MONITOR_MODE.JAMTRACK) {
|
||||
context.jamClient.SessionJamTrackSeekMs(seek);
|
||||
}
|
||||
else {
|
||||
context.jamClient.SessionTrackSeekMs(data.positionMs);
|
||||
context.jamClient.SessionTrackSeekMs(seek);
|
||||
}
|
||||
}
|
||||
|
||||
function startStopRecording() {
|
||||
|
||||
// check first if a jamtrack is loaded, and playing; if so, tell user to stop the play
|
||||
if(sessionModel.jamTracks() && context.jamClient.isSessionTrackPlaying()) {
|
||||
/**if(sessionModel.jamTracks() && context.jamClient.isSessionTrackPlaying()) {
|
||||
app.notify(
|
||||
{ title: "Can't Recording a Play JamTrack",
|
||||
text: "Stop the JamTrack before trying to recording." },
|
||||
|
|
@ -2827,7 +2937,7 @@
|
|||
true);
|
||||
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
if(sessionModel.recordingModel.isRecording()) {
|
||||
sessionModel.recordingModel.stopRecording();
|
||||
|
|
@ -2938,6 +3048,9 @@
|
|||
$(document).on("change", ".metronome-select", onMetronomeChanged)
|
||||
$metronomePlaybackSelect.metronomePlaybackMode().on(EVENTS.METRONOME_PLAYBACK_MODE_SELECTED, metronomePlaybackModeChanged)
|
||||
context.JK.helpBubble($metronomePlaybackHelp, 'metromone-playback-modes', {} , {offsetParent: $screen, width:'400px'});
|
||||
$(document).on('layout_resized', function() {
|
||||
resizeFluid();
|
||||
});
|
||||
}
|
||||
|
||||
this.initialize = function(localRecordingsDialogInstance, recordingFinishedDialogInstance, friendSelectorDialog) {
|
||||
|
|
@ -2971,6 +3084,10 @@
|
|||
$metronomePlaybackSelect = $('#metronome-playback-select')
|
||||
$metronomePlaybackHelp = $('#metronome-playback-help')
|
||||
$templatePendingMetronome = $('#template-pending-metronome');
|
||||
$myTracks = $screen.find('.session-mytracks');
|
||||
$liveTracks = $screen.find('.session-livetracks');
|
||||
$audioTracks = $screen.find('.session-recordings');
|
||||
$fluidTracks = $screen.find('.session-fluidtracks')
|
||||
|
||||
events();
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,32 @@
|
|||
}
|
||||
}
|
||||
|
||||
function recordedJamTracks() {
|
||||
if(currentSession && currentSession.claimed_recording) {
|
||||
return currentSession.claimed_recording.recording.recorded_jam_track_tracks
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function jamTrackName() {
|
||||
if (currentSession && currentSession.jam_track) {
|
||||
return currentSession.jam_track.name;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function recordedJamTrackName() {
|
||||
if(currentSession && currentSession.claimed_recording && currentSession.claimed_recording.recording.jam_track) {
|
||||
return currentSession.claimed_recording.recording.jam_track.name;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// did I open up the current JamTrack?
|
||||
function selfOpenedJamTracks() {
|
||||
return currentSession && (currentSession.jam_track_initiator_id == context.JK.currentUserId)
|
||||
|
|
@ -843,8 +869,11 @@
|
|||
this.backingTrack = backingTrack;
|
||||
this.backingTracks = backingTracks;
|
||||
this.recordedBackingTracks = recordedBackingTracks;
|
||||
this.recordedJamTracks = recordedJamTracks;
|
||||
this.setUserTracks = setUserTracks;
|
||||
this.recordedTracks = recordedTracks;
|
||||
this.jamTrackName = jamTrackName;
|
||||
this.recordedJamTrackName = recordedJamTrackName;
|
||||
this.jamTracks = jamTracks;
|
||||
this.participants = participants;
|
||||
this.joinSession = joinSession;
|
||||
|
|
|
|||
|
|
@ -30,10 +30,17 @@
|
|||
e.preventDefault();
|
||||
|
||||
if (!context.JK.currentUserId) {
|
||||
window.location = '/client#/signin';
|
||||
window.location = '/client#/checkoutSignin';
|
||||
}
|
||||
else {
|
||||
window.location = '/client#/order';
|
||||
app.user().done(function(user) {
|
||||
if(user.has_recurly_account && user.reuse_card) {
|
||||
window.location = '/client#/checkoutOrder';
|
||||
}
|
||||
else {
|
||||
window.location = '/client#/checkoutPayment';
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
var notificationPanel = null;
|
||||
var chatPanel = null;
|
||||
var me = null;
|
||||
var $sidebar = null;
|
||||
|
||||
function initializeSearchPanel() {
|
||||
$('#search_text_type').change(function() {
|
||||
|
|
@ -39,7 +40,9 @@
|
|||
function initializeFriendsPanel() {
|
||||
|
||||
$('#sidebar-search-header').hide();
|
||||
refreshFriends();
|
||||
app.user().done(function() {
|
||||
refreshFriends();
|
||||
})
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -406,11 +409,24 @@
|
|||
me = this;
|
||||
invitationDialog = invitationDialogInstance;
|
||||
textMessageDialog = textMessageDialogInstance;
|
||||
events();
|
||||
initializeSearchPanel();
|
||||
initializeFriendsPanel();
|
||||
initializeChatPanel();
|
||||
initializeNotificationsPanel();
|
||||
$sidebar = $('#sidebar-div')
|
||||
app.user()
|
||||
.done(function() {
|
||||
events();
|
||||
initializeSearchPanel();
|
||||
initializeFriendsPanel();
|
||||
initializeChatPanel();
|
||||
initializeNotificationsPanel();
|
||||
})
|
||||
.fail(function(arg1) {
|
||||
if(arg1 == "not_logged_in") {
|
||||
$('#search-input').attr('disabled', 'disabled')
|
||||
$('.sidebar .invite-friend-row').click(function() {
|
||||
app.layout.showDialog('login-required-dialog')
|
||||
});
|
||||
$sidebar.addClass('not-logged-in')
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
this.refreshFriends = refreshFriends;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ context.JK ||= {};
|
|||
|
||||
context.JK.SiteValidator = class SiteValidator
|
||||
|
||||
constructor: (site_type) ->
|
||||
constructor: (site_type, success_callback, fail_callback) ->
|
||||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@site_type = site_type
|
||||
|
|
@ -18,6 +18,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({})
|
||||
|
|
@ -53,6 +55,8 @@ context.JK.SiteValidator = class SiteValidator
|
|||
|
||||
validateSite: () =>
|
||||
unless data = this.dataToValidate()
|
||||
if @success_callback
|
||||
@success_callback(@input_div)
|
||||
return null
|
||||
this.setSiteStatus(null)
|
||||
@spinner.show()
|
||||
|
|
@ -68,11 +72,16 @@ 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)
|
||||
|
||||
|
|
@ -120,8 +129,8 @@ context.JK.SiteValidator = class SiteValidator
|
|||
|
||||
|
||||
context.JK.RecordingSourceValidator = class RecordingSourceValidator extends SiteValidator
|
||||
constructor: (site_type) ->
|
||||
super(site_type)
|
||||
constructor: (site_type, success_callback, fail_callback) ->
|
||||
super(site_type, success_callback, fail_callback)
|
||||
@recording_sources = []
|
||||
@is_rec_src = true
|
||||
@add_btn = @input_div.find('a.add-recording-source')
|
||||
|
|
|
|||
|
|
@ -981,6 +981,19 @@
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
context.JK.flash = function(msg, options) {
|
||||
options = options || {}
|
||||
|
||||
var $flash = $(context._.template($('#template-flash-notice').html(), {}, { variable: 'data' }));
|
||||
$flash.find('.flash-content').html(msg);
|
||||
$('body').prepend($flash)
|
||||
if(options.hide) {
|
||||
// slide down (take 1 sec to do it), sit for 5, then leave over 1 second
|
||||
setTimeout(function() {$flash.slideUp(1000, 'swing') }, options.hide * 1000)
|
||||
}
|
||||
}
|
||||
|
||||
context.JK.hasFlash = function () {
|
||||
var hasFlash = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
var platformName; // mac, windows, linux
|
||||
var platformDisplay; // Mac, Windows, Linux
|
||||
var platform = selectedPlatform; //MacOSX, Win32, Unix
|
||||
var platformName1, platformName2, platform1, platform2;
|
||||
var platformName1, platformName2, platform1, platform2, platformDisplay1, platformDisplay2;
|
||||
var uri = downloadUris[selectedPlatform];
|
||||
|
||||
// prepare template varaibles
|
||||
|
|
@ -21,21 +21,27 @@
|
|||
platformName = "linux";
|
||||
platformDisplay = "Linux"
|
||||
platformName1 = "mac";
|
||||
platformDisplay1 = "Mac";
|
||||
platformName2 = "windows";
|
||||
platformDisplay2 = "Windows";
|
||||
platform1 = "MacOSX";
|
||||
platform2 = "Win32"
|
||||
} else if(selectedPlatform == "Win32") {
|
||||
platformName = "windows";
|
||||
platformDisplay = "Windows";
|
||||
platformName1 = "mac";
|
||||
platformDisplay1 = "Mac";
|
||||
platformName2 = "linux"
|
||||
platformDisplay2 = "Linux";
|
||||
platform1 = "MacOSX";
|
||||
platform2 = "Unix";
|
||||
} else if(selectedPlatform == "MacOSX") {
|
||||
platformName = "mac";
|
||||
platformDisplay = "Mac";
|
||||
platformName1 = "windows";
|
||||
platformDisplay1 = "Windows";
|
||||
platformName2 = "linux";
|
||||
platformDisplay2 = "Linux";
|
||||
platform1 = "Win32";
|
||||
platform2 = "Unix";
|
||||
}
|
||||
|
|
@ -48,7 +54,9 @@
|
|||
platformName : platformName,
|
||||
platformDisplay : platformDisplay,
|
||||
platformName1 : platformName1,
|
||||
platformDisplay1 : platformDisplay1,
|
||||
platformName2 : platformName2,
|
||||
platformDisplay2 : platformDisplay2,
|
||||
platform1: platform1,
|
||||
platform2: platform2,
|
||||
uri : uri ? uri : '#',
|
||||
|
|
@ -105,9 +113,20 @@
|
|||
function removeSpinner() {
|
||||
$('body.web .spinner-large').remove();
|
||||
}
|
||||
|
||||
function flashCongratulations() {
|
||||
context.JK.flash('Congratulations!<br>Your account is ready.', {hide:10})
|
||||
}
|
||||
function listClients(congratulations) {
|
||||
isCongratulations = congratulations;
|
||||
|
||||
if(isCongratulations) {
|
||||
flashCongratulations();
|
||||
}
|
||||
else {
|
||||
//flashCongratulations();
|
||||
}
|
||||
|
||||
var rest = context.JK.Rest();
|
||||
var currentOS = context.JK.detectOS();
|
||||
var downloads = $('.downloads');
|
||||
|
|
|
|||
|
|
@ -458,8 +458,8 @@
|
|||
}
|
||||
|
||||
/** account sessions */
|
||||
.account-sessions {
|
||||
div#account-scheduled-sessions {
|
||||
.account-sessions, .account-jamtracks {
|
||||
div#account-scheduled-sessions, #account-my-jamtracks {
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow: auto;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@
|
|||
|
||||
.sample {
|
||||
margin: 3px 5px 10px 0px;
|
||||
|
||||
a.add-recording-source {
|
||||
margin-top: 2px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.sample-list {
|
||||
|
|
|
|||
|
|
@ -1,25 +1,24 @@
|
|||
@import "client/common.css.scss";
|
||||
|
||||
.checkout-navigation {
|
||||
padding: 20px 0px;
|
||||
.nav-signin, .nav-payment-info, .nav-place-order {
|
||||
width: 30%;
|
||||
margin-right:50px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.nav-signin {
|
||||
margin-left: 5%;
|
||||
}
|
||||
|
||||
.nav-place-order {
|
||||
margin-right: 5%;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.nav-text {
|
||||
font-size: 17px;
|
||||
float: left;
|
||||
color:$ColorTextDisabled;
|
||||
}
|
||||
|
||||
.nav-text.selected {
|
||||
font-weight: bold;
|
||||
color:$ColorTextHighlight;
|
||||
}
|
||||
|
||||
.nav-arrow {
|
||||
|
|
@ -28,144 +27,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.checkout-signin, .checkout-payment-info, .checkout-place-order {
|
||||
padding: 30px;
|
||||
|
||||
.signin-form {
|
||||
padding: 10px;
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.signin-password {
|
||||
margin-left: 33px;
|
||||
}
|
||||
|
||||
.login-error {
|
||||
background-color: #330000;
|
||||
border: 1px solid #990000;
|
||||
padding:4px;
|
||||
|
||||
div.actions {
|
||||
margin-top:10px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-error-msg {
|
||||
display:none;
|
||||
margin-top:10px;
|
||||
text-align:center;
|
||||
color:#F00;
|
||||
font-size:11px;
|
||||
}
|
||||
|
||||
.login-error .login-error-msg {
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
|
||||
form.payment-info {
|
||||
width: 100%;
|
||||
|
||||
input[type="text"] {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.billing-address {
|
||||
float: left;
|
||||
width: 50%;
|
||||
|
||||
h2.billing-caption {
|
||||
margin: 20px 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.billing-label {
|
||||
padding-top: 8px;
|
||||
width: 30%;
|
||||
float: left;
|
||||
text-align: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.billing-value {
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.payment-method {
|
||||
float: left;
|
||||
width: 50%;
|
||||
|
||||
h2.payment-method-caption {
|
||||
margin: 20px 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
padding-top: 8px;
|
||||
width: 35%;
|
||||
float: left;
|
||||
text-align: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
width: 60%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.save-card-checkbox {
|
||||
float:left;
|
||||
display:block;
|
||||
margin-right:5px;
|
||||
}
|
||||
}
|
||||
|
||||
.shipping-address {
|
||||
float: left;
|
||||
width: 50%;
|
||||
|
||||
h2.shipping-address-label {
|
||||
margin: 20px 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.shipping-as-billing {
|
||||
float:left;
|
||||
display:block;
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
.divBillingHelper {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.shipping-label {
|
||||
padding-top: 8px;
|
||||
width: 30%;
|
||||
float: left;
|
||||
text-align: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.shipping-value {
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.thanks-panel {
|
||||
padding: 30px;
|
||||
|
||||
|
|
@ -203,88 +64,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.order-panel {
|
||||
padding: 30px;
|
||||
|
||||
.order-header {
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.order-content {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.order-left-page {
|
||||
float: left;
|
||||
width: 60%;
|
||||
|
||||
.payment-info-page {
|
||||
padding: 5px;
|
||||
|
||||
.info-caption-link {
|
||||
.caption-text {
|
||||
float: left;
|
||||
}
|
||||
.caption-link {
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.address-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.payment-method-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
.order-items-page {
|
||||
padding: 5px;
|
||||
|
||||
.cart-item-caption {
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-item-caption#header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cart-item-price {
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-item-quantity {
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.order-right-page {
|
||||
float: right;
|
||||
width: 35%;
|
||||
text-align: center;
|
||||
|
||||
.order-total {
|
||||
color: #ed3618;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
@import "client/common.css.scss";
|
||||
#checkoutOrderScreen {
|
||||
|
||||
|
||||
p {
|
||||
font-size:12px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.order-prompt {
|
||||
color:white;
|
||||
line-height:125%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color:white;
|
||||
background-color:#4d4d4d;
|
||||
font-weight:normal;
|
||||
margin: 0 0 10px 0;
|
||||
font-size:14px;
|
||||
padding: 3px 0 3px 10px;
|
||||
height: 14px;
|
||||
line-height: 14px;
|
||||
vertical-align: middle;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.action-bar {
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
.line {
|
||||
margin:10px 0 10px;
|
||||
border-width:0 0 1px 0;
|
||||
border-color:#ccc;
|
||||
border-style:solid;
|
||||
}
|
||||
|
||||
#checkout-info-help {
|
||||
margin-right:1px;
|
||||
}
|
||||
|
||||
.billing-info-item {
|
||||
margin-bottom:3px;
|
||||
}
|
||||
|
||||
.country {
|
||||
margin-left:15px;
|
||||
}
|
||||
.billing-address {
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.order-panel {
|
||||
padding: 30px;
|
||||
min-width:730px;
|
||||
|
||||
.place-order {
|
||||
font-size: 14px;
|
||||
padding: 1px 3px;
|
||||
line-height: 15px;
|
||||
}
|
||||
|
||||
.place-order-center {
|
||||
text-align:center;
|
||||
margin:20px 0 20px;
|
||||
}
|
||||
|
||||
.change-payment-info {
|
||||
position:absolute;
|
||||
font-size:12px;
|
||||
left:180px;
|
||||
}
|
||||
|
||||
.billing-caption {
|
||||
margin-bottom:5px;
|
||||
float:left;
|
||||
position:relative;
|
||||
}
|
||||
.order-header {
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.shipping-address {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.order-help {
|
||||
margin:20px 0 30px;
|
||||
}
|
||||
.order-summary {
|
||||
padding:0 20px;
|
||||
|
||||
.billing-caption {
|
||||
float:none;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
}
|
||||
.order-items-header {
|
||||
float:left;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
.order-items-value {
|
||||
float:right;
|
||||
}
|
||||
|
||||
.order-content {
|
||||
margin-top: 20px;
|
||||
background-color:#262626;
|
||||
}
|
||||
|
||||
.order-left-page {
|
||||
float: left;
|
||||
width: 65%;
|
||||
background-color:#262626;
|
||||
border-width:0 1px 0 0;
|
||||
border-style:solid;
|
||||
border-color:#333;
|
||||
@include border_box_sizing;
|
||||
|
||||
.payment-info-page {
|
||||
|
||||
.info-caption-link {
|
||||
.caption-text {
|
||||
float: left;
|
||||
}
|
||||
.caption-link {
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.address-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
padding:0 10px;
|
||||
@include border_box_sizing;
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
.payment-method-info {
|
||||
width: 50%;
|
||||
float: left;
|
||||
padding:0 10px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
}
|
||||
.order-items-page {
|
||||
.cart-item-caption {
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
margin-bottom:10px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.cart-item-price {
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
padding:0 10px;
|
||||
margin-bottom:10px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.cart-item-quantity {
|
||||
width: 10%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
padding:0 10px;
|
||||
margin-bottom:10px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
margin-top: 10px;
|
||||
padding-left:10px;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.no-cart-items {
|
||||
}
|
||||
}
|
||||
}
|
||||
.order-right-page {
|
||||
float: left;
|
||||
width: 35%;
|
||||
text-align: left;
|
||||
background-color:#262626;
|
||||
@include border_box_sizing;
|
||||
|
||||
.grand-total {
|
||||
color: #ed3618;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
@import "client/common.css.scss";
|
||||
#checkoutPaymentScreen {
|
||||
|
||||
.payment-wrapper {
|
||||
padding:10px 30px;
|
||||
min-width:600px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size:12px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.payment-prompt {
|
||||
color:white;
|
||||
line-height:125%;
|
||||
}
|
||||
|
||||
.field.error {
|
||||
background-color: transparent !important;
|
||||
padding: 0 !important;
|
||||
border-width:0 !important;
|
||||
|
||||
li {
|
||||
list-style:none;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
color:white;
|
||||
background-color:#4d4d4d;
|
||||
font-weight:normal;
|
||||
margin: 0 0 30px 0;
|
||||
font-size:14px;
|
||||
padding-left:10px;
|
||||
|
||||
&.shipping-address-label {
|
||||
//margin-top:10px;
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
#payment_error {
|
||||
@include border_box_sizing;
|
||||
background-color: #300;
|
||||
padding: 5px;
|
||||
border: solid 1px #900;
|
||||
}
|
||||
|
||||
form.payment-info {
|
||||
width: 100%;
|
||||
display:block;
|
||||
background-color:#262626;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
input[type="text"], input[type="password"] {
|
||||
width: 90%;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
select#billing-country {
|
||||
width:90%;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
&.signed-in {
|
||||
.row.second {
|
||||
.left-side {
|
||||
width:100%;
|
||||
}
|
||||
.right-side {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.not-signed-in {
|
||||
.row.second {
|
||||
.left-side {
|
||||
display:none;
|
||||
}
|
||||
.right-side {
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#divShippingFirstName, #divShippingLastName {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.row {
|
||||
|
||||
margin-top:20px;
|
||||
width:100%;
|
||||
clear:both;
|
||||
}
|
||||
.left-side, .right-side {
|
||||
float: left;
|
||||
width: 50%;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.left-side {
|
||||
border-width:0 1px 0 0;
|
||||
border-style:solid;
|
||||
border-color:#333;
|
||||
}
|
||||
|
||||
.jamkazam-account-signup {
|
||||
.account-label {
|
||||
padding-top: 4px;
|
||||
width: 35%;
|
||||
float: left;
|
||||
text-align: left;
|
||||
padding-left: 5px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.account-value {
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
div.terms-of-service.ichecbuttons {
|
||||
margin-left:5px;
|
||||
.icheckbox_minimal {
|
||||
|
||||
float: left;
|
||||
display: block;
|
||||
margin: 5px 5px 0 0;
|
||||
}
|
||||
}
|
||||
.terms-of-service-label-holder {
|
||||
font-size:12px;
|
||||
line-height:18px;
|
||||
top:4px;
|
||||
position:relative;
|
||||
float:left;
|
||||
}
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size:12px;
|
||||
}
|
||||
.billing-address {
|
||||
|
||||
.billing-label {
|
||||
padding-top: 4px;
|
||||
width: 35%;
|
||||
float: left;
|
||||
text-align: left;
|
||||
padding-left: 5px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.billing-value {
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
}
|
||||
|
||||
.payment-method {
|
||||
|
||||
|
||||
.card-label {
|
||||
padding-top: 4px;
|
||||
width: 35%;
|
||||
float: left;
|
||||
text-align: left;
|
||||
padding-left: 5px;
|
||||
@include border_box_sizing;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.save-card-checkbox, .reuse-existing-card-checkbox {
|
||||
float:left;
|
||||
display:block;
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
label[for="reuse-existing-card"], label[for="save-card"] {
|
||||
line-height: 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.reuse-existing-card-helper {
|
||||
margin-bottom:10px;
|
||||
}
|
||||
}
|
||||
|
||||
.shipping-address {
|
||||
|
||||
.shipping-as-billing {
|
||||
float:left;
|
||||
display:block;
|
||||
margin: 0 5px 10px;
|
||||
}
|
||||
|
||||
.divBillingHelper {
|
||||
padding-top: 2px;
|
||||
|
||||
label {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.shipping-label {
|
||||
padding-top: 4px;
|
||||
width: 35%;
|
||||
float: left;
|
||||
text-align: left;
|
||||
padding-left: 5px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.shipping-value {
|
||||
width: 65%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
@import "client/common.css.scss";
|
||||
|
||||
#checkoutSignInScreen {
|
||||
|
||||
.content-holder {
|
||||
|
||||
margin-top:40px;
|
||||
color:$ColorTextTypical;
|
||||
|
||||
&.signed-in {
|
||||
.left-side, .right-side {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
&.not-signed-in {
|
||||
.already-signed-in {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.already-signed-in {
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
a.forgot-password {
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
font-size:10px;
|
||||
}
|
||||
|
||||
.signin-submit {
|
||||
margin-right:2px;
|
||||
}
|
||||
|
||||
|
||||
.signup-later-prompt {
|
||||
margin:30px 0 30px 0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.signin-prompt {
|
||||
float:right;
|
||||
text-align:left;
|
||||
margin:30px 0 15px 0;
|
||||
width:60%;
|
||||
max-width:300px;
|
||||
@include border_box_sizing;
|
||||
|
||||
span {
|
||||
text-align:left;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size:14px;
|
||||
line-height:125%;
|
||||
}
|
||||
|
||||
label {
|
||||
display:inline-block;
|
||||
width:80px;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
.login-error {
|
||||
|
||||
div.actions {
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.field {
|
||||
background-color: #330000;
|
||||
border: 1px solid #990000;
|
||||
padding:8px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
display:inline;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.login-error-msg {
|
||||
display:none;
|
||||
margin-top:10px;
|
||||
text-align:center;
|
||||
color:#F00;
|
||||
font-size:11px;
|
||||
width:60%;
|
||||
max-width:300px;
|
||||
@include border_box_sizing;
|
||||
float:right;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
|
||||
.login-error .login-error-msg {
|
||||
display:block;
|
||||
}
|
||||
|
||||
h3
|
||||
{
|
||||
color:$ColorTextHighlight;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
input {
|
||||
width:60%;
|
||||
max-width:300px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
input[name="email"] {
|
||||
margin-bottom:13px;
|
||||
}
|
||||
|
||||
.btnNext {
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.left-side {
|
||||
float:left;
|
||||
width:50%;
|
||||
@include border_box_sizing;
|
||||
border-width:0 1px 0 0;
|
||||
border-color:white;
|
||||
border-style:solid;
|
||||
text-align:right;
|
||||
padding: 0 50px;
|
||||
margin-bottom:20px;
|
||||
|
||||
.actions {
|
||||
width:60%;
|
||||
max-width:300px;
|
||||
@include border_box_sizing;
|
||||
position:relative;
|
||||
float:right;
|
||||
}
|
||||
}
|
||||
|
||||
.left-side-content {
|
||||
@include border_box_sizing;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.right-side {
|
||||
float:left;
|
||||
width:50%;
|
||||
@include border_box_sizing;
|
||||
padding: 0 50px;
|
||||
|
||||
.actions {
|
||||
width:100%;
|
||||
text-align:center;
|
||||
}
|
||||
}
|
||||
|
||||
.facebook-prompt {
|
||||
margin:40px 0 10px 0;
|
||||
float:right;
|
||||
text-align:left;
|
||||
width:249px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
}
|
||||
|
|
@ -56,6 +56,10 @@
|
|||
*= require ./jamtrack
|
||||
*= require ./shoppingCart
|
||||
*= require ./checkout
|
||||
*= require ./checkout_signin
|
||||
*= require ./checkout_payment
|
||||
*= require ./checkout_order
|
||||
*= require ./genreSelector
|
||||
*= require ./sessionList
|
||||
*= require ./searchResults
|
||||
*= require ./clientUpdate
|
||||
|
|
|
|||
|
|
@ -12,8 +12,13 @@ $ColorLinkHover: #82AEAF;
|
|||
$ColorSidebarText: #a0b9bd;
|
||||
$ColorScreenBackground: lighten($ColorUIBackground, 10%);
|
||||
$ColorTextBoxBackground: #c5c5c5;
|
||||
$ColorTextBoxDisabledBackground: #999;
|
||||
$ColorRecordingBackground: #471f18;
|
||||
|
||||
$ColorTextHighlight: white;
|
||||
$ColorTextTypical: #CCCCCC;
|
||||
$ColorTextDisabled: #AAAAAA;
|
||||
|
||||
$color1: #006AB6; /* mid blue */
|
||||
$color2: #9A9084; /* warm gray */
|
||||
$color3: #B11254; /* magenta */
|
||||
|
|
@ -292,4 +297,24 @@ $fair: #cc9900;
|
|||
}
|
||||
}
|
||||
|
||||
.badge-number {
|
||||
font-size:25px;
|
||||
color:white;
|
||||
background-color:$ColorScreenPrimary;
|
||||
width:30px;
|
||||
height:30px;
|
||||
-webkit-border-radius:50%;
|
||||
-moz-border-radius:50%;
|
||||
border-radius:50%;
|
||||
text-align:center;
|
||||
display:inline-block;
|
||||
border:2px solid white;
|
||||
margin-right:10px;
|
||||
|
||||
&.disabled {
|
||||
color:$ColorTextDisabled;
|
||||
border-color:$ColorTextDisabled;
|
||||
background-color:transparent;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -222,6 +222,10 @@
|
|||
border:none;
|
||||
-webkit-box-shadow: inset 2px 2px 3px 0px #888;
|
||||
box-shadow: inset 2px 2px 3px 0px #888;
|
||||
|
||||
&:disabled {
|
||||
background-color: $ColorTextBoxDisabledBackground;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -383,6 +387,10 @@ a.arrow-down {
|
|||
select {
|
||||
font-size:11px;
|
||||
margin-top:4px;
|
||||
|
||||
}
|
||||
.dropdown-wrapper {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
body > .flash-notice {
|
||||
|
||||
background-color:#006673;
|
||||
position:absolute;
|
||||
width:300px;
|
||||
height:100px;
|
||||
line-height: 100px;
|
||||
margin:0 auto;
|
||||
border-width:0 1px 1px;
|
||||
border-style:solid;
|
||||
border-color:white;
|
||||
text-align:center;
|
||||
left:50%;
|
||||
margin-left:-150px;
|
||||
|
||||
.flash-content {
|
||||
color:white;
|
||||
font-size:20px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -8,6 +8,10 @@
|
|||
background-repeat: no-repeat;
|
||||
background-position: bottom left;
|
||||
border: 1px solid $translucent1;
|
||||
|
||||
&.not-logged-in {
|
||||
opacity:0.6;
|
||||
}
|
||||
}
|
||||
.homecard.createsession {
|
||||
background-image: url(/assets/content/bkg_home_create.jpg);
|
||||
|
|
@ -38,7 +42,7 @@
|
|||
background-image: url(/assets/content/bkg_home_bands.jpg);
|
||||
}
|
||||
.homecard.musicians {
|
||||
background-image: url(/assets/content/bkg_home_musicians.jpg);
|
||||
background-image: url(/assets/content/bkg_home_guitar.jpg);
|
||||
}
|
||||
.homecard.jamtrack {
|
||||
background-image: url(/assets/content/bkg_home_jamtracks.jpg);
|
||||
|
|
@ -94,7 +98,7 @@
|
|||
background-image: url(/assets/content/bkg_home_bands_x.jpg);
|
||||
}
|
||||
.homecard.musicians.hover {
|
||||
background-image: url(/assets/content/bkg_home_musicians_x.jpg);
|
||||
background-image: url(/assets/content/bkg_home_guitar_x.jpg);
|
||||
}
|
||||
.homecard.jamtrack.hover {
|
||||
background-image: url(/assets/content/bkg_home_jamtracks_x.jpg);
|
||||
|
|
|
|||
|
|
@ -322,6 +322,10 @@ input[type="text"], input[type="password"]{
|
|||
border:none;
|
||||
padding:3px;
|
||||
font-size:15px;
|
||||
|
||||
&:disabled {
|
||||
background-color: $ColorTextBoxDisabledBackground;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
|
@ -388,6 +392,24 @@ textarea {
|
|||
padding:5px;
|
||||
border: solid 1px #900;
|
||||
|
||||
.error-text {
|
||||
display:block;
|
||||
font-size:11px;
|
||||
color:#F00;
|
||||
margin:10px 0 0;
|
||||
}
|
||||
|
||||
&.transparent {
|
||||
background-color:transparent;
|
||||
padding:0;
|
||||
border-width:0px;
|
||||
|
||||
.error-text {
|
||||
margin:5px 0 0;
|
||||
font-size:14px;
|
||||
font-weight:bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error input {
|
||||
|
|
@ -399,12 +421,6 @@ textarea {
|
|||
display:none;
|
||||
}
|
||||
|
||||
.error .error-text {
|
||||
display:block;
|
||||
font-size:11px;
|
||||
color:#F00;
|
||||
margin:10px 0 0;
|
||||
}
|
||||
.grey {
|
||||
color:#999;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,74 @@
|
|||
@import 'common';
|
||||
|
||||
#jamtrackLanding {
|
||||
ul {
|
||||
li {
|
||||
margin: 1px 4px 1px 4em;
|
||||
font-size:9px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-columns {
|
||||
h2 {
|
||||
font-size: 16pt;
|
||||
font-weight:300;
|
||||
font-style: bolder;
|
||||
font-family: verdana;
|
||||
text-transform: lowercase;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.free-jamtrack {
|
||||
font-size: 11pt;
|
||||
padding: 3px;
|
||||
@include border-radius(7px);
|
||||
background-color:$ColorScreenPrimary;
|
||||
text-align: center;
|
||||
vertical-align: center;
|
||||
}
|
||||
|
||||
.what, .howto {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
p {
|
||||
font-size: 12pt !important;
|
||||
font-weight: normal;
|
||||
line-height: 16px;
|
||||
color: #dddddd;
|
||||
* {
|
||||
font-size: 10pt !important;
|
||||
font-weight: normal;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
.about {
|
||||
@include border_box_sizing;
|
||||
float: left;
|
||||
width: 50%;
|
||||
> * {
|
||||
margin: 4px;
|
||||
}
|
||||
}
|
||||
.browse {
|
||||
@include border_box_sizing;
|
||||
float: left;
|
||||
width: 50%;
|
||||
> * {
|
||||
margin: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#jamtrackScreen {
|
||||
.jamtrack-header {
|
||||
background-color: #4c4c4c;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
height: 2em;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
a.jamtrack_help {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
|
|
@ -11,6 +81,8 @@
|
|||
|
||||
.jamtrack-content {
|
||||
text-align: center;
|
||||
border: 1px solid #222222;
|
||||
padding: 2px
|
||||
}
|
||||
|
||||
.no-jamtracks-msg {
|
||||
|
|
@ -23,14 +95,16 @@
|
|||
}
|
||||
|
||||
.jamtrack-detail {
|
||||
@include border_box_sizing;
|
||||
float: left;
|
||||
width: 50%;
|
||||
width: 30%;
|
||||
padding: 10px 0px;
|
||||
|
||||
.detail-label {
|
||||
width: 40%;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
font-weight: 400;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
|
|
@ -56,15 +130,17 @@
|
|||
|
||||
.jamtrack-detail-btn {
|
||||
cursor: pointer;
|
||||
margin-top: 5px;
|
||||
margin-top: 7px;
|
||||
margin-right: 5px;
|
||||
padding-top: 5px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack-tracks {
|
||||
@include border_box_sizing;
|
||||
float: left;
|
||||
width: 25%;
|
||||
width: 50%;
|
||||
padding: 10px 0px;
|
||||
|
||||
.tracks-caption {
|
||||
|
|
@ -78,6 +154,7 @@
|
|||
|
||||
.instrument-image {
|
||||
float: left;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.instrument-desc {
|
||||
|
|
@ -88,8 +165,9 @@
|
|||
}
|
||||
|
||||
.jamtrack-action {
|
||||
@include border_box_sizing;
|
||||
float: left;
|
||||
width: 25%;
|
||||
width: 20%;
|
||||
padding: 10px 0px;
|
||||
text-align: center;
|
||||
|
||||
|
|
@ -113,4 +191,30 @@
|
|||
width: 60%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#jamtrack-license-dialog {
|
||||
.dialog-inner {
|
||||
height: auto;
|
||||
.content-body {
|
||||
max-height: auto;
|
||||
.content-body-scroller {
|
||||
height: 350px;
|
||||
.paragraph {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
overflow: hidden;
|
||||
}
|
||||
border: 1px solid #222;
|
||||
margin: 4px 4px 8px 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack_buttons {
|
||||
margin: 8px 4px 12px 4px;
|
||||
}
|
||||
|
||||
.capitalize {
|
||||
text-transform: capitalize
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
background-color:#4c4c4c;
|
||||
min-height:20px;
|
||||
position:relative;
|
||||
min-width:690px;
|
||||
}
|
||||
|
||||
.pending-metronome {
|
||||
|
|
@ -55,7 +56,11 @@
|
|||
|
||||
.recording-position {
|
||||
display:inline-block;
|
||||
width:80%;
|
||||
width:calc(100% - 27px - 47px); // 27 accounts for play arrow, 47px acconts for the total time (0:00)
|
||||
|
||||
position:absolute;
|
||||
left:0;
|
||||
margin-left:27px;
|
||||
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size:11px;
|
||||
|
|
@ -150,6 +155,7 @@
|
|||
|
||||
.session-add {
|
||||
margin-top:9px;
|
||||
margin-right:10px;
|
||||
}
|
||||
.session-add a {
|
||||
vertical-align:top;
|
||||
|
|
@ -193,6 +199,139 @@
|
|||
color:#ffcc00;
|
||||
cursor:help;
|
||||
}
|
||||
|
||||
|
||||
.leave {
|
||||
margin-right:25px;
|
||||
}
|
||||
|
||||
$mytracks-minwidth: 180px;
|
||||
$livetracks-minwidth:180px;
|
||||
$otheraudio-minwidth:195px;
|
||||
$otheraudio-open-minwidth:230px;
|
||||
|
||||
.session-mytracks {
|
||||
padding-left:15px;
|
||||
float:left;
|
||||
display:inline-block;
|
||||
width:$mytracks-minwidth;
|
||||
border-right:solid 1px #666;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.session-fluidtracks {
|
||||
width:calc(100% - #{$mytracks-minwidth});
|
||||
position:relative;
|
||||
float:left;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
.session-livetracks {
|
||||
padding-left:15px;
|
||||
padding-right:15px;
|
||||
float:left;
|
||||
display:inline-block;
|
||||
min-width:$livetracks-minwidth;
|
||||
max-width:calc(100% - #{$otheraudio-minwidth});
|
||||
width:calc(100% - #{$otheraudio-minwidth});
|
||||
border-right:solid 1px #666;
|
||||
@include border_box_sizing;
|
||||
|
||||
&[media-state="open"] {
|
||||
width:calc(100% - #{$otheraudio-open-minwidth});
|
||||
max-width:calc(100% - #{$otheraudio-open-minwidth});
|
||||
min-width:#{$livetracks-minwidth};
|
||||
}
|
||||
|
||||
.recording {
|
||||
left: 50%;
|
||||
margin-left: -67px;
|
||||
}
|
||||
|
||||
.recording-controls {
|
||||
min-width:230px;
|
||||
}
|
||||
}
|
||||
|
||||
.session-recordings {
|
||||
padding-left:15px;
|
||||
padding-right:15px;
|
||||
display:inline-block;
|
||||
max-width:calc(100% - #{$livetracks-minwidth});
|
||||
min-width:#{$otheraudio-minwidth};
|
||||
width:#{$otheraudio-minwidth};
|
||||
float:left;
|
||||
@include border_box_sizing;
|
||||
|
||||
&[media-state="open"] {
|
||||
width:$otheraudio-open-minwidth;
|
||||
min-width:$otheraudio-open-minwidth;
|
||||
max-width:calc(100% - #{$livetracks-minwidth});
|
||||
}
|
||||
|
||||
|
||||
.recording.metronome-mode {
|
||||
margin-left:-100px;
|
||||
}
|
||||
}
|
||||
|
||||
#tracks .when-empty.livetracks {
|
||||
margin: 0px;
|
||||
padding:0px;
|
||||
display:block;
|
||||
padding-top: 125px;
|
||||
vertical-align:middle;
|
||||
text-align:center;
|
||||
}
|
||||
#tracks .when-empty.recordings {
|
||||
//padding-top: 137px;
|
||||
text-align:left;
|
||||
padding-top:6px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
#tracks .when-empty a {
|
||||
text-decoration: underline;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.session-add {
|
||||
margin-top:9px;
|
||||
margin-bottom:8px;
|
||||
font-size:16px;
|
||||
height: 22px;
|
||||
min-height: 22px;
|
||||
max-height: 22px;
|
||||
}
|
||||
|
||||
.session-add a {
|
||||
color:#ccc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.session-add a img {
|
||||
vertical-align:bottom;
|
||||
}
|
||||
|
||||
.session-tracks-scroller {
|
||||
position:relative;
|
||||
overflow-x:auto;
|
||||
overflow-y:hidden;
|
||||
width:100%;
|
||||
height:370px;
|
||||
float:left;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
.play-controls-holder {
|
||||
width:100%;
|
||||
text-align:center;
|
||||
|
||||
.recording {
|
||||
left:50%;
|
||||
margin-left:-46.5%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -334,84 +473,6 @@ table.vu td {
|
|||
margin-left:15px;
|
||||
}
|
||||
|
||||
.leave {
|
||||
margin-right:25px;
|
||||
}
|
||||
|
||||
.session-mytracks {
|
||||
margin-left:15px;
|
||||
float:left;
|
||||
display:inline-block;
|
||||
width:19%;
|
||||
min-width:165px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.session-livetracks {
|
||||
margin-left:15px;
|
||||
float:left;
|
||||
display:inline-block;
|
||||
width:35%;
|
||||
min-width:220px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.session-recordings {
|
||||
margin-left:15px;
|
||||
display:inline-block;
|
||||
width:35%;
|
||||
min-width:220px;
|
||||
}
|
||||
|
||||
#tracks .when-empty.livetracks {
|
||||
margin: 0px;
|
||||
padding:0px;
|
||||
display:block;
|
||||
padding-top: 125px;
|
||||
vertical-align:middle;
|
||||
text-align:center;
|
||||
}
|
||||
#tracks .when-empty.recordings {
|
||||
//padding-top: 137px;
|
||||
text-align:left;
|
||||
padding-top:6px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
#tracks .when-empty a {
|
||||
text-decoration: underline;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.session-add {
|
||||
margin-top:9px;
|
||||
margin-bottom:8px;
|
||||
font-size:16px;
|
||||
height: 22px;
|
||||
min-height: 22px;
|
||||
max-height: 22px;
|
||||
}
|
||||
|
||||
.session-add a {
|
||||
color:#ccc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.session-add a img {
|
||||
vertical-align:bottom;
|
||||
}
|
||||
|
||||
|
||||
.session-tracks-scroller {
|
||||
position:relative;
|
||||
overflow-x:auto;
|
||||
overflow-y:hidden;
|
||||
width:100%;
|
||||
height:370px;
|
||||
float:left;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -750,7 +811,6 @@ table.vu td {
|
|||
margin-top:15px;
|
||||
padding:3px;
|
||||
height:19px;
|
||||
width:95%;
|
||||
background-color:#242323;
|
||||
position:absolute;
|
||||
text-align:center;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
@import "client/common";
|
||||
|
||||
|
||||
table.findsession-table, table.local-recordings, table.open-jam-tracks, table.open-backing-tracks, #account-session-detail {
|
||||
table.findsession-table, table.local-recordings, table.open-jam-tracks, table.open-backing-tracks, table.cart-items, #account-session-detail, table.payment-table {
|
||||
|
||||
.latency-unacceptable {
|
||||
width: 50px;
|
||||
|
|
@ -64,7 +64,7 @@ table.findsession-table, table.local-recordings, table.open-jam-tracks, table.op
|
|||
text-align:center;
|
||||
}
|
||||
}
|
||||
table.findsession-table, table.local-recordings, table.open-jam-tracks, table.open-backing-tracks {
|
||||
table.findsession-table, table.local-recordings, table.open-jam-tracks, table.open-backing-tracks, table.cart-items, table.payment-table {
|
||||
width:98%;
|
||||
height:10%;
|
||||
font-size:11px;
|
||||
|
|
|
|||
|
|
@ -29,9 +29,7 @@
|
|||
}
|
||||
|
||||
.cart-item-caption {
|
||||
width: 50%;
|
||||
text-align: left;
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cart-item-caption#header {
|
||||
|
|
@ -39,21 +37,15 @@
|
|||
}
|
||||
|
||||
.cart-item-price {
|
||||
width: 15%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.cart-item-quantity {
|
||||
width: 15%;
|
||||
text-align: right;
|
||||
float: left;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.cart-item-actions {
|
||||
width: 20%;
|
||||
text-align: center;
|
||||
float: left;
|
||||
//text-align: center;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@
|
|||
|
||||
background-color: $ColorElementPrimary;
|
||||
|
||||
&.not-logged-in {
|
||||
opacity:0.6;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
|
|
|
|||