diff --git a/admin/app/views/admin/test_drive_packages/_test_drive_package_teacher_fields.html.slim b/admin/app/views/admin/test_drive_packages/_test_drive_package_teacher_fields.html.slim index 40039250b..fdb47b3ba 100644 --- a/admin/app/views/admin/test_drive_packages/_test_drive_package_teacher_fields.html.slim +++ b/admin/app/views/admin/test_drive_packages/_test_drive_package_teacher_fields.html.slim @@ -3,6 +3,6 @@ ol.nested-fields //= f.input :test_drive_package, :required=>true, value: @test_drive_package, include_blank: true = f.input :user, :required=>true, collection: User.where(is_a_teacher: true, phantom: false), include_blank: true - = f.input :short_bio + = f.input :short_bio_temp = link_to_remove_association "Delete Teacher", f, class: 'button', style: 'margin-left:10px' diff --git a/db/manifest b/db/manifest index 8a56701fd..685148214 100755 --- a/db/manifest +++ b/db/manifest @@ -356,4 +356,5 @@ remove_stripe_acct_id.sql track_user_on_lesson.sql audio_in_music_notations.sql lesson_time_tracking.sql -packaged_test_drive.sql \ No newline at end of file +packaged_test_drive.sql +packaged_test_drive2.sql \ No newline at end of file diff --git a/db/up/packaged_test_drive2.sql b/db/up/packaged_test_drive2.sql new file mode 100644 index 000000000..c5c7209c9 --- /dev/null +++ b/db/up/packaged_test_drive2.sql @@ -0,0 +1,2 @@ +ALTER TABLE lesson_booking_slots ADD COLUMN from_package BOOL DEFAULT FALSE; +ALTER TABLE lesson_bookings ADD COLUMN test_drive_package_choice_id VARCHAR(64) REFERENCES test_drive_package_choices(id); diff --git a/ruby/lib/jam_ruby/models/lesson_booking.rb b/ruby/lib/jam_ruby/models/lesson_booking.rb index ca52d8131..03268b051 100644 --- a/ruby/lib/jam_ruby/models/lesson_booking.rb +++ b/ruby/lib/jam_ruby/models/lesson_booking.rb @@ -45,6 +45,7 @@ module JamRuby belongs_to :default_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :default_slot_id, inverse_of: :defaulted_booking, :dependent => :destroy belongs_to :counter_slot, class_name: "JamRuby::LessonBookingSlot", foreign_key: :counter_slot_id, inverse_of: :countered_booking, :dependent => :destroy belongs_to :school, class_name: "JamRuby::School" + belongs_to :test_drive_package_choice, class_name: "JamRuby::TestDrivePackageChoice" has_many :lesson_booking_slots, class_name: "JamRuby::LessonBookingSlot", :dependent => :destroy has_many :lesson_sessions, class_name: "JamRuby::LessonSession", :dependent => :destroy has_many :lesson_package_purchases, class_name: "JamRuby::LessonPackagePurchase", :dependent => :destroy @@ -139,6 +140,9 @@ module JamRuby booked_price end + def no_slots + default_slot.from_package + end def alt_slot found = nil @@ -193,12 +197,16 @@ module JamRuby self.counterer = proposer self.countered_at = Time.now self.sent_counter_reminder = false + + if self.default_slot.from_package + self.default_slot = slot + end #self.status = STATUS_COUNTERED self.save end def automatically_default_slot - if is_requested? + if is_requested? && default_slot.nil? if lesson_booking_slots.length > 0 self.default_slot = lesson_booking_slots[0] end @@ -680,8 +688,10 @@ module JamRuby end def validate_lesson_booking_slots - if lesson_booking_slots.length == 0 || lesson_booking_slots.length == 1 - errors.add(:lesson_booking_slots, "must have two times specified") + if test_drive_package_choice.nil? + if lesson_booking_slots.length == 0 || lesson_booking_slots.length == 1 + errors.add(:lesson_booking_slots, "must have two times specified") + end end end @@ -711,19 +721,22 @@ module JamRuby !!school end + def self.book_packaged_test_drive(user, teacher, description, test_drive_package_choice) + book_test_drive(user, teacher, LessonBookingSlot.packaged_slots, description, test_drive_package_choice) + end def self.book_free(user, teacher, lesson_booking_slots, description) self.book(user, teacher, LessonBooking::LESSON_TYPE_FREE, lesson_booking_slots, false, 30, PAYMENT_STYLE_ELSEWHERE, description) end - def self.book_test_drive(user, teacher, lesson_booking_slots, description) - self.book(user, teacher, LessonBooking::LESSON_TYPE_TEST_DRIVE, lesson_booking_slots, false, 30, PAYMENT_STYLE_ELSEWHERE, description) + def self.book_test_drive(user, teacher, lesson_booking_slots, description, test_drive_package_choice = nil) + self.book(user, teacher, LessonBooking::LESSON_TYPE_TEST_DRIVE, lesson_booking_slots, false, 30, PAYMENT_STYLE_ELSEWHERE, description, test_drive_package_choice) end def self.book_normal(user, teacher, lesson_booking_slots, description, recurring, payment_style, lesson_length) self.book(user, teacher, LessonBooking::LESSON_TYPE_PAID, lesson_booking_slots, recurring, lesson_length, payment_style, description) end - def self.book(user, teacher, lesson_type, lesson_booking_slots, recurring, lesson_length, payment_style, description) + def self.book(user, teacher, lesson_type, lesson_booking_slots, recurring, lesson_length, payment_style, description, test_drive_package_choice = nil) lesson_booking = nil LessonBooking.transaction do @@ -739,6 +752,7 @@ module JamRuby lesson_booking.payment_style = payment_style lesson_booking.description = description lesson_booking.status = STATUS_REQUESTED + lesson_booking.test_drive_package_choice = test_drive_package_choice if lesson_booking.teacher && lesson_booking.teacher.teacher.school lesson_booking.school = lesson_booking.teacher.teacher.school end diff --git a/ruby/lib/jam_ruby/models/lesson_booking_slot.rb b/ruby/lib/jam_ruby/models/lesson_booking_slot.rb index 6c64a39e6..d9d38ca47 100644 --- a/ruby/lib/jam_ruby/models/lesson_booking_slot.rb +++ b/ruby/lib/jam_ruby/models/lesson_booking_slot.rb @@ -74,6 +74,18 @@ module JamRuby (Time.now + APP_CONFIG.minimum_lesson_booking_hrs * 60 * 60) end + # create a canned slot for a TestDrivePackage. The most important thing here is that it expires in 30 days + def self.packaged_slots + slot = LessonBookingSlot.new + slot.from_package = true + slot.preferred_day = Date.today + 30 + slot.slot_type = LessonBookingSlot::SLOT_TYPE_SINGLE + slot.hour = 1 + slot.minute = 0 + slot.timezone = 'America/Chicago' + [slot] + end + def scheduled_times(needed_sessions, minimum_start_time) #puts "NEEDED SESSIONS #{needed_sessions} #{minimum_start_time}" diff --git a/ruby/lib/jam_ruby/models/lesson_package_purchase.rb b/ruby/lib/jam_ruby/models/lesson_package_purchase.rb index d0e592358..a38976b93 100644 --- a/ruby/lib/jam_ruby/models/lesson_package_purchase.rb +++ b/ruby/lib/jam_ruby/models/lesson_package_purchase.rb @@ -55,7 +55,7 @@ module JamRuby def to_s - "#{name} (#{amount_charged})" + "#{name}" end def name diff --git a/ruby/lib/jam_ruby/models/lesson_session.rb b/ruby/lib/jam_ruby/models/lesson_session.rb index e4225be2e..13f47819f 100644 --- a/ruby/lib/jam_ruby/models/lesson_session.rb +++ b/ruby/lib/jam_ruby/models/lesson_session.rb @@ -66,7 +66,6 @@ module JamRuby validate :validate_canceled, :if => :canceling validate :validate_autocancel, :if => :autocanceling - after_save :after_counter, :if => :countering after_save :manage_slot_changes after_create :create_charge @@ -444,10 +443,6 @@ module JamRuby self.lesson_booking.save(:validate => false) end - def after_counter - send_counter(@countered_lesson, @countered_slot) - end - def scheduled_start if music_session music_session.scheduled_start @@ -458,10 +453,12 @@ module JamRuby end def send_counter(countered_lesson, countered_slot) - if countered_slot.is_teacher_created? - UserMailer.student_lesson_counter(countered_lesson, countered_slot).deliver - else - UserMailer.teacher_lesson_counter(countered_lesson, countered_slot).deliver + if !lesson_booking.errors.any? + if countered_slot.is_teacher_created? + UserMailer.student_lesson_counter(countered_lesson, countered_slot).deliver + else + UserMailer.teacher_lesson_counter(countered_lesson, countered_slot).deliver + end end self.countering = false end @@ -522,6 +519,7 @@ module JamRuby self.countering_flag = false end + def validate_accepted if self.status_was != STATUS_REQUESTED && self.status_was != STATUS_COUNTERED self.errors.add(:status, "This session is already #{self.status_was}.") @@ -632,7 +630,7 @@ module JamRuby # if the school owner is a teacher, show his bookings too extra_teacher = " OR lesson_sessions.teacher_id = '#{user.teacher.id}'" end - query = query.where('lesson_sessions.teacher_id in (?)' + extra_teacher, user.owned_school.teachers.map {|t| t.user.id}) + query = query.where('lesson_sessions.teacher_id in (?)' + extra_teacher, user.owned_school.teachers.map { |t| t.user.id }) query = query.where('lesson_sessions.status = ? OR lesson_sessions.status = ?', LessonSession::STATUS_REQUESTED, LessonSession::STATUS_COUNTERED) else # this is a normal teacher (not a school owner) @@ -819,7 +817,7 @@ module JamRuby self.countered_lesson = self self.status = STATUS_COUNTERED #if !update_all - self.counter_slot = slot + self.counter_slot = slot #end if self.save #if update_all && !lesson_booking.counter(self, proposer, slot) @@ -832,6 +830,7 @@ module JamRuby raise ActiveRecord::Rollback end + send_counter(@countered_lesson, @countered_slot) message = '' if message.nil? msg = ChatMessage.create(slot.proposer, music_session, message, ChatMessage::CHANNEL_LESSON, nil, slot.recipient, self, "New Time Proposed") Notification.send_lesson_message('counter', self, slot.is_teacher_created?) diff --git a/ruby/lib/jam_ruby/models/test_drive_package.rb b/ruby/lib/jam_ruby/models/test_drive_package.rb index d85f1b086..bfdbd138f 100644 --- a/ruby/lib/jam_ruby/models/test_drive_package.rb +++ b/ruby/lib/jam_ruby/models/test_drive_package.rb @@ -13,6 +13,9 @@ module JamRuby #validate :teacher_count + def lesson_package_type + LessonPackageType.package_for_test_drive_count(package_type.to_i) + end def teacher_count if package_type != test_drive_package_teachers.length self.errors.add(:test_drive_package_teachers, "wrong number of teachers specified for the given package type #{package_type}") diff --git a/ruby/lib/jam_ruby/models/test_drive_package_choice.rb b/ruby/lib/jam_ruby/models/test_drive_package_choice.rb index 569e1e352..17e9eec87 100644 --- a/ruby/lib/jam_ruby/models/test_drive_package_choice.rb +++ b/ruby/lib/jam_ruby/models/test_drive_package_choice.rb @@ -5,9 +5,9 @@ module JamRuby @@log = Logging.logger[TestDrivePackageChoice] belongs_to :test_drive_package, class_name: "JamRuby::TestDrivePackage" - belongs_to :user, class_name: "JamRuby::User" - has_many :test_drive_package_choice_teachers, class_name: "JamRuby::TestDrivePackageChoiceTeacher", foreign_key: :teacher_id - + belongs_to :user, class_name: "JamRuby::User", foreign_key: :user_id, inverse_of: :test_drive_package_choices + has_many :test_drive_package_choice_teachers, class_name: "JamRuby::TestDrivePackageChoiceTeacher", inverse_of: :test_drive_package_choice + has_many :lesson_bookings, class_name: "JamRuby::LessonBooking" end end diff --git a/ruby/lib/jam_ruby/models/test_drive_package_choice_teacher.rb b/ruby/lib/jam_ruby/models/test_drive_package_choice_teacher.rb index 02397f886..356880073 100644 --- a/ruby/lib/jam_ruby/models/test_drive_package_choice_teacher.rb +++ b/ruby/lib/jam_ruby/models/test_drive_package_choice_teacher.rb @@ -4,7 +4,7 @@ module JamRuby @@log = Logging.logger[TestDrivePackageChoiceTeacher] - belongs_to :test_drive_package_choice, class_name: "JamRuby::TestDrivePackageChoice" + belongs_to :test_drive_package_choice, class_name: "JamRuby::TestDrivePackageChoice", inverse_of: :test_drive_package_choice_teachers belongs_to :teacher, class_name: "JamRuby::User", foreign_key: :teacher_id end diff --git a/ruby/lib/jam_ruby/models/test_drive_package_teacher.rb b/ruby/lib/jam_ruby/models/test_drive_package_teacher.rb index ab5d29fcf..2b0208189 100644 --- a/ruby/lib/jam_ruby/models/test_drive_package_teacher.rb +++ b/ruby/lib/jam_ruby/models/test_drive_package_teacher.rb @@ -4,8 +4,8 @@ module JamRuby @@log = Logging.logger[TestDrivePackageTeacher] - attr_accessor :short_bio_temp - attr_accessible :user_id, :test_drive_package_id, :short_bio, as: :admin + attr_writer :short_bio_temp + attr_accessible :user_id, :test_drive_package_id, :short_bio, :short_bio_temp, as: :admin belongs_to :test_drive_package, class_name: "JamRuby::TestDrivePackage" belongs_to :user, class_name: "JamRuby::User" @@ -18,12 +18,19 @@ module JamRuby # silly pass through for activeadmin. We pass short_bio set here on to teacher def after_save if user && user.teacher - user.teacher.short_bio = short_bio - user.teacher.save! + if @another_bio.present? + user.teacher.short_bio = @another_bio + user.teacher.save! + end end end - def short_bio + def short_bio_temp=(short_bio) + self.updated_at = Time.now + self.short_bio = short_bio + @another_bio = short_bio + end + def short_bio_temp if user && user.teacher user.teacher.short_bio end diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index ad92ac057..2fe371f8b 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -41,7 +41,7 @@ module JamRuby attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection # updating_password corresponds to a lost_password - attr_accessor :validate_instruments, :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field, :mods_json, :expecting_gift_card + attr_accessor :test_drive_packaging, :validate_instruments, :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field, :mods_json, :expecting_gift_card belongs_to :icecast_server_group, class_name: "JamRuby::IcecastServerGroup", inverse_of: :users, foreign_key: 'icecast_server_group_id' @@ -176,6 +176,8 @@ module JamRuby has_many :teacher_lesson_bookings, :class_name => "JamRuby::LessonBooking", :foreign_key => "teacher_id", inverse_of: :teacher has_many :teacher_distributions, :class_name => "JamRuby::TeacherDistribution", :foreign_key => "teacher_id", inverse_of: :teacher has_many :teacher_payments, :class_name => "JamRuby::TeacherPayment", :foreign_key => "teacher_id", inverse_of: :teacher + has_many :test_drive_package_choice_teachers, :class_name => "JamRuby::TestDrivePackageChoiceTeacher", :foreign_key => "teacher_id" + has_many :test_drive_package_choices, :class_name => "JamRuby::TestDrivePackageChoice", :foreign_key => "user_id", inverse_of: :user belongs_to :desired_package, :class_name => "JamRuby::LessonPackageType", :foreign_key => "lesson_package_type_id", inverse_of: :user_desired_packages # used to hold whether user last wanted test drive 4/2/1 # Shopping carts @@ -203,7 +205,7 @@ module JamRuby has_many :taught_lessons, :class_name => "JamRuby::LessonSession", inverse_of: :teacher, foreign_key: :teacher_id belongs_to :school, :class_name => "JamRuby::School", inverse_of: :students has_one :owned_school, :class_name => "JamRuby::School", inverse_of: :user - + has_many :test_drive_package_choices, :class_name =>"JamRuby::TestDrivePackageChoice" has_many :jamblasters_users, class_name: "JamRuby::JamblasterUser" has_many :jamblasters, class_name: 'JamRuby::Jamblaster', through: :jamblasters_users @@ -1076,6 +1078,27 @@ module JamRuby end end + def handle_test_drive_package(package, details) + self.test_drive_packaging = true + choice = TestDrivePackageChoice.new + choice.user = self + choice.test_drive_package = package + details[:teachers].each do |teacher| + teacher_choice = TestDrivePackageChoiceTeacher.new + teacher_choice.teacher = User.find(teacher[:id]) + choice.test_drive_package_choice_teachers << teacher_choice + end + + choice.save! + + choice.test_drive_package_choice_teachers.each do |teacher_choice| + booking = LessonBooking.book_packaged_test_drive(self, teacher_choice.teacher, "Please suggest a time that works for you.", choice) + if booking.errors.any? + raise "unable to create booking in package user:#{self.email}" + end + end + end + # throws ActiveRecord::RecordNotFound if instrument is invalid # throws an email delivery error if unable to connect out to SMTP def self.signup(options) @@ -1107,6 +1130,9 @@ module JamRuby school_id = options[:school_id] school_interest = options[:school_interest] origin = options[:origin] + test_drive_package_details = options[:test_drive_package] + + test_drive_package = TestDrivePackage.find_by_name(test_drive_package_details[:name]) school = School.find(school_id) if school_id user = User.new @@ -1351,6 +1377,7 @@ module JamRuby user.save end if affiliate_referral_id.present? + user.handle_test_drive_package(test_drive_package, test_drive_package_details) if test_drive_package if user.is_a_student UserMailer.student_welcome_message(user).deliver @@ -1981,9 +2008,10 @@ module JamRuby customer end - def card_approved(token, zip, booking_id) + def card_approved(token, zip, booking_id, test_drive_package_choice_id = nil) approved_booking = nil + choice = nil found_uncollectables = nil User.transaction do self.stripe_token = token if token @@ -1999,6 +2027,13 @@ module JamRuby end end + if test_drive_package_choice_id + choice = TestDrivePackageChoice.find(test_drive_package_choice_id) + choice.lesson_bookings.each do|booking| + booking.card_approved + end + end + if uncollectables.count > 0 found_uncollectables = uncollectables uncollectables.update_all(billing_should_retry: true) @@ -2007,7 +2042,7 @@ module JamRuby end end end - [approved_booking, found_uncollectables] + [approved_booking, found_uncollectables, choice] end def update_name(name) @@ -2038,6 +2073,7 @@ module JamRuby purchase = nil lesson_package_type = nil uncollectables = nil + choice = nil User.transaction do if params[:name].present? @@ -2046,12 +2082,15 @@ module JamRuby end end - booking, uncollectables = card_approved(params[:token], params[:zip], params[:booking_id]) + booking, uncollectables, choice = card_approved(params[:token], params[:zip], params[:booking_id], params[:test_drive_package_choice_id]) if params[:test_drive] self.reload if booking lesson_package_type = booking.resolved_test_drive_package + elsif choice + choice.test_drive_package.lesson_package_type end + if lesson_package_type.nil? lesson_package_type = LessonPackageType.test_drive_4 end @@ -2071,7 +2110,7 @@ module JamRuby end - {lesson: booking, test_drive: test_drive, purchase: purchase, lesson_package_type: lesson_package_type, uncollectables: uncollectables} + {lesson: booking, test_drive: test_drive, purchase: purchase, lesson_package_type: lesson_package_type, uncollectables: uncollectables, package: choice} end def requested_test_drive(teacher = nil) diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb index 893a4a2b5..86dbaeb1f 100644 --- a/ruby/spec/factories.rb +++ b/ruby/spec/factories.rb @@ -108,6 +108,7 @@ FactoryGirl.define do association :user, factory: :user price_per_lesson_60_cents 3000 price_per_month_60_cents 3000 + short_bio 'abc def uueue doc neck' end factory :musician_instrument, :class => JamRuby::MusicianInstrument do diff --git a/ruby/spec/jam_ruby/models/user_spec.rb b/ruby/spec/jam_ruby/models/user_spec.rb index 6a40ce0bc..41ec0b1b8 100644 --- a/ruby/spec/jam_ruby/models/user_spec.rb +++ b/ruby/spec/jam_ruby/models/user_spec.rb @@ -905,6 +905,30 @@ describe User do uncollectable.is_card_declined?.should be_false end end + describe "handle_test_drive_package" do + let(:user) {FactoryGirl.create(:user)} + + it "4-count" do + package_size = 4 + package = FactoryGirl.create(:test_drive_package, :four_pack) + detail = {} + teachers = [] + detail[:teachers] = teachers + package.test_drive_package_teachers.each do |package_teacher| + teachers << {id: package_teacher.user.id} + end + user.handle_test_drive_package(package, detail) + + user.errors.any?.should be_false + + LessonSession.where(user_id: user.id).count.should eql package_size + user.student_lesson_bookings.count.should eql package_size + user.student_lesson_bookings.each do |booking| + booking.status.should eql LessonBooking::STATUS_REQUESTED + booking.card_presumed_ok.should be_false + end + end + end =begin describe "update avatar" do diff --git a/web/app/assets/javascripts/everywhere/everywhere.js b/web/app/assets/javascripts/everywhere/everywhere.js index a6e5a721d..29eba67cd 100644 --- a/web/app/assets/javascripts/everywhere/everywhere.js +++ b/web/app/assets/javascripts/everywhere/everywhere.js @@ -271,7 +271,6 @@ var show = false; - console.log("data.newScreen", data.newScreen) if (data.newScreen && activate.indexOf(data.newScreen) > -1) { show = true; } diff --git a/web/app/assets/javascripts/helpBubbleHelper.js b/web/app/assets/javascripts/helpBubbleHelper.js index df99b0bac..ea23a8f73 100644 --- a/web/app/assets/javascripts/helpBubbleHelper.js +++ b/web/app/assets/javascripts/helpBubbleHelper.js @@ -237,6 +237,8 @@ } helpBubble.testDrivePackageGo = function($element, $offsetParent, package_type) { - return context.JK.prodBubble($element, 'test-drive-package-go', {plural: package_type != '1'}, bigHelpDarkOptions({offsetParent:$offsetParent, width:260, positions:['bottom']})) + return context.JK.prodBubble($element, 'test-drive-package-go', {plural: package_type != '1'}, bigHelpDarkOptions({offsetParent:$offsetParent, width:300, duration:13000, positions:['bottom'], postShow: function(container) { + subtlePulse(container) + }})) } })(window, jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 1c00aac3e..bd8dd4f7a 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -2133,6 +2133,15 @@ }) } + function getTestDrivePackageChoice(options) { + options = options || {} + return $.ajax({ + type: "GET", + url: '/api/test_drive_package_choice/' + options.id, + dataType: "json", + contentType: 'application/json' + }) + } function getLessonBooking(options) { options = options || {} @@ -2717,6 +2726,7 @@ this.portOverCarts = portOverCarts; this.bookLesson = bookLesson; this.attachRecordingToLesson = attachRecordingToLesson; + this.getTestDrivePackageChoice = getTestDrivePackageChoice; this.getLessonBooking = getLessonBooking; this.getUnprocessedLesson = getUnprocessedLesson; this.getUnprocessedLessonOrIntent = getUnprocessedLessonOrIntent; diff --git a/web/app/assets/javascripts/landing/landing.js b/web/app/assets/javascripts/landing/landing.js index de23401db..3cc86db70 100644 --- a/web/app/assets/javascripts/landing/landing.js +++ b/web/app/assets/javascripts/landing/landing.js @@ -20,6 +20,9 @@ //= require jquery.ba-bbq //= require jquery.icheck //= require jquery.exists +//= require jquery.manageVsts +//= require jquery.lessonSessionActions +//= require ResizeSensor //= require AAA_Log //= require AAC_underscore //= require alert @@ -35,6 +38,7 @@ //= require ui_helper //= require jam_rest //= require ga +//= require recordingModel //= require web/signup_helper //= require web/signin_helper //= require web/signin diff --git a/web/app/assets/javascripts/react-components/JamClassScreen.js.jsx.coffee b/web/app/assets/javascripts/react-components/JamClassScreen.js.jsx.coffee index 2c68b006b..dd0a7227d 100644 --- a/web/app/assets/javascripts/react-components/JamClassScreen.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/JamClassScreen.js.jsx.coffee @@ -114,7 +114,10 @@ LessonTimerActions = context.LessonTimerActions text: "Start time for session set to 65 mins ago" }))) else if data.lessonAction == 'enter-payment' - window.location.href = "/client#/jamclass/lesson-payment/lesson-booking_#{lessonId}" + if lesson.lesson_booking.test_drive_package_choice_id? + window.location.href = "/client#/jamclass/lesson-payment/package_#{lesson.lesson_booking.test_drive_package_choice_id}" + else + window.location.href = "/client#/jamclass/lesson-payment/lesson-booking_#{lessonId}" else context.JK.showAlert('unknown lesson action', 'The option in the menu is unknown') @@ -527,7 +530,10 @@ LessonTimerActions = context.LessonTimerActions else unreadMessages = null - if lessonData.status == 'countered' + if lessonData.lesson_booking.no_slots + timeStmt = 'No time has been scheduled yet' + + else if lessonData.status == 'countered' timeStmt = lessonData.counter_slot.pretty_scheduled_start_with_timezone else timeStmt = lessonData.music_session.pretty_scheduled_start_with_timezone diff --git a/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee b/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee index 023b9a66b..5d09da185 100644 --- a/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee @@ -50,6 +50,10 @@ UserStore = context.UserStore slot.creatorRoleRelative = "your" slot.mySlot = @mySlot(slot) + # for a test drive packaged delai, while we do create a slot to satisfy certain aspects of the backend, it's not 'real'. So we say 'noSlots' until someone has proposed something + noSlots: () -> + @state.booking?.no_slots + processBooking:(booking) -> booking.neverAccepted = booking.accepter_id? booking.isCounter = booking.counter_slot? && booking.status != 'canceled' && booking.status != 'suspended' @@ -58,6 +62,7 @@ UserStore = context.UserStore booking.isRequested = booking.status == 'requested' && !booking.isCounter booking.isCanceled = booking.status == 'canceled' booking.isSuspended = booking.status == 'suspended' + if booking.isCounter if booking.counter_slot['is_teacher_created?'] booking.countererId = booking.teacher_id @@ -472,7 +477,10 @@ UserStore = context.UserStore selfLastToAct: () -> if @isRequested() - @studentViewing() + if @isCounter() + @counterer().id == @myself().id + else + @studentViewing() else if @isCounter() @counterer().id == @myself().id else if @isCanceled() @@ -647,7 +655,8 @@ UserStore = context.UserStore selfLastToAct: this.selfLastToAct(), counterErrors: this.state.counterErrors, cancelErrors: this.state.cancelErrors, - focusedLesson: this.focusedLesson() + focusedLesson: this.focusedLesson(), + noSlots: this.noSlots() } render: () -> @@ -813,9 +822,15 @@ UserStore = context.UserStore createDetail: () -> if @hasFocusedLesson() || !@isRecurring() if @onlyOption() && @rescheduling() - detail = `

You are proposing to change the date/time of the lesson currently scheduled for {this.slotTime(this.state.booking.default_slot)}

` + if @noSlots() + detail = `

You are proposing a date/time for this lesson.

` + else + detail = `

You are proposing to change the date/time of the lesson currently scheduled for {this.slotTime(this.state.booking.default_slot)}

` else - detail = `

Your {this.lessonDesc()} will take place this {this.slotTime(this.state.booking.default_slot)}

` + if @noSlots() + detail = `

Your lesson has no scheduled time yet.

` + else + detail = `

Your {this.lessonDesc()} will take place this {this.slotTime(this.state.booking.default_slot)}

` else if @onlyOption() && @rescheduling() detail = `

You are proposing to change the date/time of the lesson currently scheduled for {this.slotTime(this.state.booking.default_slot)}

` @@ -916,13 +931,20 @@ UserStore = context.UserStore else action = `

Has requested a {this.lessonDesc()} lesson, for which you will be paid {this.lessonPaymentAmt()}.

` + + if @noSlots() + slots = [] + else + slots = [this.state.booking.default_slot] + if this.state.booking.alt_slot? + slots.push(this.state.booking.alt_slot) `
{this.userHeader(this.other())} {action} {this.slotMessage(this.state.booking.default_slot)}
- +
` renderTeacherApproved: () -> diff --git a/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee b/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee index 96b12a084..a56e05525 100644 --- a/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/LessonBookingDecision.js.jsx.coffee @@ -145,7 +145,10 @@ multipleOptions: () -> if this.props.initial - !(!this.props.counter && this.props.selfLastToAct) + if this.props.noSlots + false + else + !(!this.props.counter && this.props.selfLastToAct) else if this.props.counter !this.props.selfLastToAct else @@ -156,16 +159,19 @@ #showUpdateAll = !this.props.initial if (!this.props.initial && !this.props.counter) || this.props.selfLastToAct - userPromptHeader = `

Would you like to change this lesson?

` + userPromptHeader = `

Would you like to update this lesson?

` messagePromptHeader = `

Send message to {this.props.otherRole} with your update.

` else userPromptHeader = `

How do you want to handle this request?

` messagePromptHeader = `

Send message to {this.props.otherRole} with your response.

` if this.props.slot_decision == 'counter' - if this.props.update_all - actionBtnText = "PROPOSE ALTERNATE TIME FOR ALL LESSONS" + if this.props.is_recurring && this.props.update_all + actionBtnText = "PROPOSE TIME FOR ALL LESSONS" else - actionBtnText = "PROPOSE ALTERNATE TIME" + if @props.noSlots + actionBtnText = 'PROPOSE TIME' + else + actionBtnText = "PROPOSE ALTERNATE TIME" else if this.props.slot_decision == 'decline' @@ -199,7 +205,7 @@ Time: : - +
* Time will be local to {window.JK.currentTimezone()} {errorText} @@ -239,7 +245,10 @@ slots = [] if !(this.props.counter && this.props.selfLastToAct) - proposeAltLabelText = "Propose alternate day/time" + if this.props.noSlots + proposeAltLabelText = 'Propose a day/time' + else + proposeAltLabelText = "Propose alternate day/time" for slot, i in @props.slots if this.props.is_recurring @@ -255,7 +264,11 @@ {slotDetail} `) else - proposeAltLabelText = "Propose new alternate day/time" + if this.props.noSlots + proposeAltLabelText = 'Propose a day/time' + else + proposeAltLabelText = "Propose new alternate day/time" + # if you have issued a counter, you should be able to withdraw it # TODO diff --git a/web/app/assets/javascripts/react-components/LessonPayment.js.jsx.coffee b/web/app/assets/javascripts/react-components/LessonPayment.js.jsx.coffee index e299a0780..0c4fd7578 100644 --- a/web/app/assets/javascripts/react-components/LessonPayment.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/LessonPayment.js.jsx.coffee @@ -53,7 +53,8 @@ UserStore = context.UserStore billingInUS: true, userWantsUpdateCC: false, "test-drive": false, - teacher: null + teacher: null, + package: null } beforeHide: (e) -> @@ -75,6 +76,9 @@ UserStore = context.UserStore rest.getUserDetail({id: parsed.teacher_id}).done((response) => @teacherLoaded(response)).fail((jqXHR) => @failedTeacher(jqXHR)) else if parsed['test-drive'] logger.debug("test-drive lesson payment; no teacher/booking in context") + else if parsed['package-choice'] + logger.debug("TestDrive package selected " + parsed.package_id) + rest.getTestDrivePackageChoice({id: parsed.package_id}).done((response) => @packageLoaded(response)).fail((jqXHR) => @failedPackage(jqXHR)) else logger.error("unknown state for lesson-payment") window.location.href = '/client#/jamclass' @@ -92,6 +96,7 @@ UserStore = context.UserStore result['test-drive'] = false result['lesson-booking'] = false result['teacher-intent'] = false + result['package-choice'] = false bits = id.split('_') if bits.length == 1 @@ -105,6 +110,9 @@ UserStore = context.UserStore else if type == 'teacher' result['teacher-intent'] = true result.teacher_id = bits[1] + else if type == 'package' + result['package-choice'] = true + result.package_id = bits[1] logger.debug("LessonPayment: parseId " + JSON.stringify(result)) @@ -119,7 +127,7 @@ UserStore = context.UserStore @setState({billingInUS: checked}) resetState: () -> - @setState({updating: false, lesson: null, teacher: null, "test-drive": false, "lesson-booking" : false, "teacher-intent": false}) + @setState({updating: false, lesson: null, teacher: null, "test-drive": false, "lesson-booking" : false, "teacher-intent": false, package: null, "package-choice": null}) lessonBookingLoaded: (response) -> @setState({updating: false}) @@ -149,6 +157,18 @@ UserStore = context.UserStore text: 'Something has gone wrong. Please try refreshing the page.' }) + packageLoaded: (response) -> + @setState({updating: false}) + logger.debug("package loaded", response) + @setState({package: response}) + + failedPackage: (jqXHR) -> + @setState({updating: false}) + @app.layout.notify({ + title: 'unable to load package info', + text: 'Something has gone wrong. Please try refreshing the page.' + }) + onBack: (e) -> e.preventDefault() window.location.href = '/client#/teachers/search' @@ -253,7 +273,7 @@ UserStore = context.UserStore @state.lesson?.lesson_type == 'paid' isTestDrive: () -> - @state['test-drive'] == true || @state.lesson?.lesson_type == 'test-drive' || @state['teacher-intent'] + @state['test-drive'] == true || @state.lesson?.lesson_type == 'test-drive' || @state['teacher-intent'] || @state['package-choice'] == true attemptPurchase: (token) -> if this.state.billingInUS @@ -264,6 +284,7 @@ UserStore = context.UserStore zip: zip, test_drive: @isTestDrive(), booking_id: @state.lesson?.id, + test_drive_package_choice_id: @state.package?.id normal: @isNormal() } @@ -304,6 +325,8 @@ UserStore = context.UserStore teacher_id = response.test_drive.teacher_id if testDriveCount == '1' text = "You have purchased 1 TestDrive credit and have used it to request a JamClass with #{@state.teacher.name}. The teacher has received your request and should respond shortly." + else if response.package? + text = "Each teacher has received your request and should respond shortly." else text = "You have purchased #{testDriveCount} TestDrive credits and have used 1 credit to request a JamClass with #{@state.teacher.name}. The teacher has received your request and should respond shortly." location = "/client#/jamclass" @@ -326,7 +349,7 @@ UserStore = context.UserStore text = "You now have #{testDriveCount} TestDrive credits that you can take with #{testDriveCount} different teachers.

We've taken you to the Teacher Search screen, so you can search for teachers right for you." location = "/client#/teachers/search" - context.JK.Banner.showNotice("Test Drive Purchased",text) + context.JK.Banner.showNotice("TestDrive Purchased",text) window.location = location else context.JK.Banner.showNotice("Something Went Wrong", "Please email support@jamkazam.com and indicate that your attempt to buy a TestDrive failed") @@ -392,7 +415,7 @@ UserStore = context.UserStore {name} ` else - if @state.lesson? || @state['test-drive'] || @state.teacher? + if @state.lesson? || @state['test-drive'] || @state.teacher? || @state['package-choice'] == true if @state.teacher? photo_url = @state.teacher.photo_url name = @state.teacher.name @@ -406,6 +429,42 @@ UserStore = context.UserStore {name} ` + else if @state.package? + teachers = [] + teachersHolder = [] + count = 0 + for teacher_choice in @state.package.teachers + + if count == 2 + teachersHolder.push( + `
+ {teachers} +
`) + teachers = [] + teacher = teacher_choice.user + photo_url = teacher.photo_url + name = teacher.name + + if !photo_url? + photo_url = '/assets/shared/avatar_generic.png' + + teachers.push( + `
+
+ +
+
{teacher.first_name}
{teacher.last_name}
+
`) + count++ + + teachersHolder.push( + `
+ {teachers} +
`) + teacherDetails = `
+ {teachersHolder} +
+
` if @state.lesson? lesson_length = @state.lesson.lesson_length @@ -415,6 +474,7 @@ UserStore = context.UserStore lesson_type = 'test-drive' + if @isTestDrive() if @reuseStoredCard() @@ -423,14 +483,26 @@ UserStore = context.UserStore header = `

enter payment info for test drive

` bookingInfo = `

` - if this.state.user.lesson_package_type_id == 'test-drive' - explanation = `You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entitles you to take 4 private online music lessons - 1 each from 4 different instructors in the JamClass instructor community. The price of this TestDrive package is $49.99.` - else if this.state.user.lesson_package_type_id == 'test-drive-1' - explanation =`You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entitles you to take 1 private online music lesson from an instructor in the JamClass instructor community. The price of this TestDrive package is $14.99.` - else if this.state.user.lesson_package_type_id == 'test-drive-2' - explanation =`You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entitles you to take 2 private online music lessons - 1 each from 2 different instructors in the JamClass instructor community. The price of this TestDrive package is $29.99.` + if this.state['package-choice'] + if this.state.package? + + if @state.package.teachers.length == 1 + explanation = `You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entities you to take a private online music lesson from this instructor. The price of this TestDrive is $14.99. If you have scheduling conflicts with this instructors, we will help you choose another teacher as a replacement.` + else if @state.package.teachers.length == 2 + explanation = `You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entities you to take 2 private online music lessons - 1 each from these 2 instructors. The price of this TestDrive is $29.99. If you have scheduling conflicts with any of these instructors, we will help you choose another teacher as a replacement.` + else if @state.package.teachers.length == 4 + explanation = `You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entities you to take 4 private online music lessons - 1 each from these 4 instructors. The price of this TestDrive is $49.99. If you have scheduling conflicts with any of these instructors, we will help you choose another teacher as a replacement.` + else + alert("unknown package type") else - alert("You do not have a test drive package selected") + if this.state.user.lesson_package_type_id == 'test-drive' + explanation = `You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entitles you to take 4 private online music lessons - 1 each from 4 different instructors in the JamClass instructor community. The price of this TestDrive package is $49.99.` + else if this.state.user.lesson_package_type_id == 'test-drive-1' + explanation =`You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entitles you to take 1 private online music lesson from an instructor in the JamClass instructor community. The price of this TestDrive package is $14.99.` + else if this.state.user.lesson_package_type_id == 'test-drive-2' + explanation =`You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entitles you to take 2 private online music lessons - 1 each from 2 different instructors in the JamClass instructor community. The price of this TestDrive package is $29.99.` + else + alert("You do not have a test drive package selected") bookingDetail = `

{explanation} diff --git a/web/app/assets/javascripts/react-components/TestDrivePackageDialog.js.jsx.coffee b/web/app/assets/javascripts/react-components/TestDrivePackageDialog.js.jsx.coffee index 1f2a7f893..26dfcaea1 100644 --- a/web/app/assets/javascripts/react-components/TestDrivePackageDialog.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/TestDrivePackageDialog.js.jsx.coffee @@ -22,13 +22,33 @@ context = window getInitialState: () -> { - target: null, - page_data: null + target: null, + page_data: null } componentDidMount: () -> @root = $(@getDOMNode()) + @dialog = @root.closest('.dialog') + + renderTeacher: (teacher) -> + photo_url = '/assets/shared/avatar_generic.png' + if teacher.photo_url? + photo_url = teacher.photo_url + + `

+
+ +
+
+ {teacher.first_name} +
+ {teacher.last_name} +
+
+ +
+
` doCancel: (e) -> e.preventDefault() @@ -43,55 +63,66 @@ context = window checked = @root.find('input[type="checkbox"]:checked') if checked.length != 2 - context.JK.Banner.showNotice('hold on there', 'Please select 2 teachers.') + window.JK.Banner.showAlert('hold on there', 'Please select 2 teachers.') return if @state.target == '1' checked = @root.find('input[type="checkbox"]:checked') if checked.length != 1 - context.JK.Banner.showNotice('hold on there', 'Please select a teacher.') + window.JK.Banner.showAlert('hold on there', 'Please select 1 teacher.') return teachers = [] - console.log("STATE TIME", @state) - if @state.page_data?.package?.teachers? - for teacher in @state.page_data.package.teachers - teachers.push(@teacher(teacher.name, teacher.photo_url, teacher.id)) $.each(checked, (i, node) => ( $node = $(node) - teachers.push($node.data('teacher')) + teacherId = $node.attr('data-teacher-id') + for teacher in @state.page_data.package.teachers + if teacher.id == teacherId + teachers.push(teacher) + break )) - @root.data('result', { package_type: @state.target, teachers: teachers }) + @dialog.data('result', {package_type: @state.target, teachers: teachers}) + @app.layout.closeDialog('test-drive-package-dialog') render: () -> - if @state.target == '2' help = `

- Check the boxes under the 2 instructors you want to select for your TestDrive package. Then click the Select button below. + Check the boxes under the 2 instructors you want to select for your TestDrive package. Then click the Select + button below.

` else - help = + help = `

- Check the box under the instructor you want to select for your TestDrive package. Then click the Select button below. + Check the box under the instructor you want to select for your TestDrive package. Then click the Select button + below.

` teachers = [] + if @state.page_data?.package?.teachers? + for teacher in @state.page_data.package.teachers + teachers.push(@renderTeacher(teacher)) + teacherHolderClasses = {"teacher-holder" : true, "two": teachers.length == 2, "four": teachers.length == 4} + dialogInnerClasses = {"dialog-inner": true, "two": teachers.length == 2, "four": teachers.length == 4} `

select instructors

-
+
{help} - {teachers} +
+ {teachers} +
+
+
CANCEL diff --git a/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingMiddlePage.js.jsx.coffee b/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingMiddlePage.js.jsx.coffee index bb1d8366a..893c1f5fc 100644 --- a/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingMiddlePage.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingMiddlePage.js.jsx.coffee @@ -20,15 +20,23 @@ selector: (count, e) -> e.preventDefault() - context.JK.app.layout.showDialog('test-drive-package-dialog').one(contexnt.JK.EVENTS.DIALOG_CLOSED, (e, data) => + # cheesy way to pass the page data to the dialog + window.page_data = @props + + window.JK.app.layout.showDialog('test-drive-package-dialog', {d1: count.toString()}).one(window.JK.EVENTS.DIALOG_CLOSED, (e, data) => #... code if !data.canceled - console.log("dialog closed. result", data.result) + console.log("dialog closed. result", data) # dialog wasn't cancelled, so let's check the value of our result: @setState(data.result) + @setState({modified: true}) + window.teacherModifications = data.result.teachers - setTimeout((() => context.JK.prodBubble($('.preview-area.jam-class'), 'body', data.result.package_type)), 1500) + $ctaBox = $('.preview-area.jam-class') + $.scrollTo($ctaBox, {duration: 500, offset: 0}) + + setTimeout((() => window.JK.HelpBubbleHelper.testDrivePackageGo($ctaBox, 'body', data.result.package_type)), 2500) ) componentDidMount: () -> @@ -59,7 +67,7 @@ `

Like the TestDrive concept, but 4 teachers is too many for you?

diff --git a/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingPage.js.jsx.coffee b/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingPage.js.jsx.coffee index 1b7130f5b..54926608d 100644 --- a/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingPage.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/landing/JamClassStudentLandingPage.js.jsx.coffee @@ -46,7 +46,34 @@ rest = context.JK.Rest() onClick={this.ctaClick}>{ctaButtonText}
` + if @props.package? + ctaBoxContents = `
+

Sign up for this amazing TestDrive offer now!

+

When you sign up below, we will ask you to pay for your TestDrive package, and then we'll forward + your lesson requests to these teachers for scheduling.

+ +

We will not share your email. See our privacy + policy

+ {register} +

We'll give you 1:1 help to get set up and ready to go with our free app.

+
` + else + + ctaBoxContents = `
+

Sign up now. You have no obligation to buy anything. Signing up makes you eligible for our TestDrive + offers.

+ +

After signing up, you can search our community of world-class instructors. If you book a TestDrive lesson + you can choose to TestDrive 4, 2, or 1 teachers at that time.

+ +

We will not share your email. See our privacy + policy

+ {register} +

And pick your teachers now!

+ +

We'll give you 1:1 help to get set up and ready to go with our free app.

+
` `
@@ -71,20 +98,7 @@ rest = context.JK.Rest()
Sign Up for TestDrive
-
-

Sign up now. You have no obligation to buy anything. Signing up makes you eligible for our TestDrive - offers.

- -

After signing up, you can search our community of world-class instructors. If you book a TestDrive lesson - you can choose to TestDrive 4, 2, or 1 teachers at that time.

- -

We will not share your email. See our privacy - policy

- {register} -

And pick your teachers now!

- -

We'll give you 1:1 help to get set up and ready to go with our free app.

-
+ {ctaBoxContents}
@@ -156,10 +170,28 @@ rest = context.JK.Rest() password = $form.find('input[name="password"]').val() terms = $form.find('input[name="terms"]').is(':checked') - rest.signup({email: email, password: password, first_name: null, last_name: null, terms: terms, student: true}) + test_drive_package = null + + if @props.package + test_drive_package ={} + if window.teacherModifications? + teachers = window.window.teacherModifications + else + teachers = @props.package.teachers + test_drive_package.name = @props.package.name + test_drive_package.teachers = teachers + + rest.signup({email: email, password: password, first_name: null, last_name: null, terms: terms, student: true, test_drive_package: test_drive_package}) .done((response) => @setState({done: true}) - context.location = '/client#/jamclass/searchOptions' + if test_drive_package? + choice = response.test_drive_package_choices?[0] + if choice? + context.location = '/client#/jamclass/lesson-payment/package_' + choice.id + else + context.location = '/client#/jamclass/searchOptions' + else + context.location = '/client#/jamclass/searchOptions' ).fail((jqXHR) => @setState({processing: false}) if jqXHR.status == 422 diff --git a/web/app/assets/javascripts/web/web.js b/web/app/assets/javascripts/web/web.js index a5ec3c545..6bad6ced2 100644 --- a/web/app/assets/javascripts/web/web.js +++ b/web/app/assets/javascripts/web/web.js @@ -23,7 +23,11 @@ //= require jquery.exists //= require jquery.visible //= require jquery.lessonSessionActions +//= require jquery.manageVsts +//= require jquery.scrollTo +//= require jquery.pulse //= require howler.core.js +//= require ResizeSensor //= require AAA_Log //= require AAC_underscore //= require alert @@ -59,6 +63,7 @@ //= require jam_track_preview //= require landing/init //= require landing/signup +//= require recordingModel //= require web/downloads //= require web/congratulations //= require web/sessions diff --git a/web/app/assets/stylesheets/client/help.css.scss b/web/app/assets/stylesheets/client/help.css.scss index 13ebed700..50f816a6c 100644 --- a/web/app/assets/stylesheets/client/help.css.scss +++ b/web/app/assets/stylesheets/client/help.css.scss @@ -1,7 +1,7 @@ @import "client/common"; //body.jam, body.web, .dialog{ -html { +html body { .bt-wrapper { font-size: 14px; font-family: 'Raleway', Arial, Helvetica, sans-serif; @@ -15,6 +15,8 @@ html { margin:1em; line-height:150%; font-size:14px; + width:auto; + @include border_box_sizing; } ul { font-size:14px; @@ -153,6 +155,9 @@ html { width:180px; } + .test-drive-package-go { + width:300px; + } .help-hover-recorded-tracks, .help-hover-stream-mix, .help-hover-recorded-backing-tracks { diff --git a/web/app/assets/stylesheets/client/react-components/LessonPayment.css.scss b/web/app/assets/stylesheets/client/react-components/LessonPayment.css.scss index 7aede7590..fb1c64100 100644 --- a/web/app/assets/stylesheets/client/react-components/LessonPayment.css.scss +++ b/web/app/assets/stylesheets/client/react-components/LessonPayment.css.scss @@ -95,6 +95,27 @@ -moz-border-radius:24px; border-radius:24px; } + .teacher-subheader { + .avatar { + margin:10px 0 0 0; + } + float:left; + width:100px; + text-align:center; + } + .teacher-holder { + display:inline-block; + } + .teacher-header { + &.packaged { + margin:40px 0 20px 0; + text-align:center; + } + } + .teacher-name-packaged { + color:$ColorTextTypical; + overflow: hidden; + } .teacher-name { font-size:16px; display:inline-block; diff --git a/web/app/assets/stylesheets/dialogs/testDrivePackageDialog.css.scss b/web/app/assets/stylesheets/dialogs/testDrivePackageDialog.css.scss new file mode 100644 index 000000000..4cadcf5c2 --- /dev/null +++ b/web/app/assets/stylesheets/dialogs/testDrivePackageDialog.css.scss @@ -0,0 +1,85 @@ +@import "client/common"; + +#test-drive-package-dialog { + //width: 700px; + min-width:400px; + width:auto; + + h3 { + color:white; + margin-bottom:20px; + } + .dialog-inner { + width: auto; + &.two { + width:400px; + } + &.four { + width:600px; + } + height:100%; + @include border_box_sizing; + margin-top: -29px; + padding: 50px 25px 25px; + } + + div[data-react-class="TestDrivePackageDialog"] { + + } + .TestDrivePackageDialog { + height:100%; + } + .teacher-select { + float:left; + } + .actions { + text-align:center; + } + + .teacher-select { + width: 120px; + text-align:center; + margin-bottom:20px; + } + + .avatar { + display: inline-block; + text-align:center; + padding: 1px; + width: 48px; + height: 48px; + background-color: #ed4818; + margin: 4px 0px 7px 0; + -webkit-border-radius: 24px; + -moz-border-radius: 24px; + border-radius: 24px; + float: none; + + } + .avatar img { + width: 48px; + height: 48px; + -webkit-border-radius: 24px; + -moz-border-radius: 24px; + border-radius: 24px; + + } + + .username { + margin-bottom:10px; + } + + .teacher-holder { + text-align:center; + margin:auto; + margin-top:20px; + + &.two { + width:242px; + } + + &.four { + width:482px; + } + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/landings/individual_jamtrack.css.scss b/web/app/assets/stylesheets/landings/individual_jamtrack.css.scss index dce28bbb0..cf19b8a6a 100644 --- a/web/app/assets/stylesheets/landings/individual_jamtrack.css.scss +++ b/web/app/assets/stylesheets/landings/individual_jamtrack.css.scss @@ -512,7 +512,7 @@ body.web.individual_jamtrack { p { line-height: 150%; - width: 100% !important; + width: 100% ; } .bottom-banner { @@ -1056,6 +1056,14 @@ body.web.individual_jamtrack { } } + .other-options { + margin-top:20px; + border:1px solid $copy-color-on-dark; + padding:20px; + ul { + margin-bottom:0; + } + } .teacher-option { margin-bottom:20px; height: 98px; @@ -1078,6 +1086,7 @@ body.web.individual_jamtrack { display: inline-block; width: 140px; margin-right: 20px; + text-align:center; } .avatar { @@ -1087,7 +1096,7 @@ body.web.individual_jamtrack { width: 64px; height: 64px; background-color: #ed4818; - margin: 4px 8px 7px 0; + margin: 4px 0px 7px 0; -webkit-border-radius: 32px; -moz-border-radius: 32px; border-radius: 32px; diff --git a/web/app/assets/stylesheets/web/main.css.scss b/web/app/assets/stylesheets/web/main.css.scss index 686b0c2bf..369e9b1ca 100644 --- a/web/app/assets/stylesheets/web/main.css.scss +++ b/web/app/assets/stylesheets/web/main.css.scss @@ -8,6 +8,9 @@ p, div { white-space: normal; } +.dialog { + position:fixed !important; +} body.web { background-repeat: repeat-x; diff --git a/web/app/assets/stylesheets/web/web.css b/web/app/assets/stylesheets/web/web.css index b5b4707c4..eaeff73fe 100644 --- a/web/app/assets/stylesheets/web/web.css +++ b/web/app/assets/stylesheets/web/web.css @@ -29,7 +29,6 @@ *= require web/downloads *= require users/signinCommon *= require dialogs/dialog -*= require client/help *= require landings/partner_agreement_v1 *= require web/affiliate_links *= require_directory ../landings diff --git a/web/app/controllers/api_lesson_bookings_controller.rb b/web/app/controllers/api_lesson_bookings_controller.rb index fc6833dd5..5a0dbba4b 100644 --- a/web/app/controllers/api_lesson_bookings_controller.rb +++ b/web/app/controllers/api_lesson_bookings_controller.rb @@ -18,6 +18,12 @@ class ApiLessonBookingsController < ApiController end + def show_choice + @choice = TestDrivePackageChoice.find(params[:id]) + + raise JamPermissionError, "You do not have permission to this data" if @choice.user != current_user + end + def create if params[:lesson_type] == LessonBooking::LESSON_TYPE_FREE diff --git a/web/app/controllers/api_stripe_controller.rb b/web/app/controllers/api_stripe_controller.rb index c3c9db0e9..d888fa369 100644 --- a/web/app/controllers/api_stripe_controller.rb +++ b/web/app/controllers/api_stripe_controller.rb @@ -16,6 +16,7 @@ class ApiStripeController < ApiController @normal = data[:normal] @lesson_package_type = data[:lesson_package_type] @uncollectables = data[:uncollectables] + @package = data[:package] end end diff --git a/web/app/controllers/api_users_controller.rb b/web/app/controllers/api_users_controller.rb index 3f0f547ec..d01735772 100644 --- a/web/app/controllers/api_users_controller.rb +++ b/web/app/controllers/api_users_controller.rb @@ -93,7 +93,8 @@ class ApiUsersController < ApiController school_id: params[:school_id], school_interest: params[:school_interest], affiliate_referral_id: cookies[:affiliate_visitor], - origin: origin_cookie + origin: origin_cookie, + test_drive_package: params[:test_drive_package] } options = User.musician_defaults(request.remote_ip, ApplicationHelper.base_uri(request) + "/confirm", any_user, options) diff --git a/web/app/controllers/landings_controller.rb b/web/app/controllers/landings_controller.rb index 50f8fd109..9e98723d1 100644 --- a/web/app/controllers/landings_controller.rb +++ b/web/app/controllers/landings_controller.rb @@ -87,7 +87,7 @@ class LandingsController < ApplicationController teachers = [] package.test_drive_package_teachers.each do |package_teacher| teacher = package_teacher.user - teachers.push({id: teacher.id, name: teacher.name, biography: teacher.teacher.biography, photo_url: teacher.photo_url}) + teachers.push({id: teacher.id, name: teacher.name, first_name: teacher.first_name,last_name: teacher.last_name, biography: teacher.teacher.short_bio, photo_url: teacher.photo_url}) end package_data[:teachers] = teachers diff --git a/web/app/views/api_lesson_bookings/show.rabl b/web/app/views/api_lesson_bookings/show.rabl index 4947183bd..08ef80a45 100644 --- a/web/app/views/api_lesson_bookings/show.rabl +++ b/web/app/views/api_lesson_bookings/show.rabl @@ -1,21 +1,21 @@ object @lesson_booking -attributes :id, :status, :lesson_type, :payment_style, :recurring, :teacher_id, :description, :lesson_length, :created_at, :user_id, :active, :accepter_id, :canceler_id, :cancel_message, :booked_price, :card_presumed_ok +attributes :id, :status, :lesson_type, :payment_style, :recurring, :teacher_id, :description, :lesson_length, :created_at, :user_id, :active, :accepter_id, :canceler_id, :cancel_message, :booked_price, :card_presumed_ok, :no_slots child(:lesson_booking_slots => :slots) { - attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone + attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone, :from_package } child(:default_slot => :default_slot) { - attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone + attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone, :from_package } child(:alt_slot => :alt_slot) { - attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone + attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone, :from_package } child(:counter_slot => :counter_slot) { - attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone + attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone, :from_package } diff --git a/web/app/views/api_lesson_bookings/show_choice.rabl b/web/app/views/api_lesson_bookings/show_choice.rabl new file mode 100644 index 000000000..d6af292ed --- /dev/null +++ b/web/app/views/api_lesson_bookings/show_choice.rabl @@ -0,0 +1,13 @@ +object @choice + +attributes :id + +child(:test_drive_package => :package) { + attributes :package_type +} + +child(:test_drive_package_choice_teachers => :teachers) { + child(:teacher) { + attributes :id, :first_name, :last_name, :name, :photo_url + } +} \ No newline at end of file diff --git a/web/app/views/api_lesson_sessions/show.rabl b/web/app/views/api_lesson_sessions/show.rabl index ab3068ec1..d0582dfad 100644 --- a/web/app/views/api_lesson_sessions/show.rabl +++ b/web/app/views/api_lesson_sessions/show.rabl @@ -14,13 +14,13 @@ end child(:lesson_booking => :lesson_booking) { - attributes :card_presumed_ok + attributes :card_presumed_ok, :test_drive_package_choice_id, :no_slots } child(:counter_slot => :counter_slot) { - attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone + attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone, :from_package node :pretty_scheduled_start_with_timezone do |slot| pretty_scheduled_start_slot(slot, true) end diff --git a/web/app/views/api_stripe/store.rabl b/web/app/views/api_stripe/store.rabl index 82b7d0726..bbf5e8fcc 100644 --- a/web/app/views/api_stripe/store.rabl +++ b/web/app/views/api_stripe/store.rabl @@ -14,6 +14,13 @@ if @test_drive end +if @package + node :package do |lesson| + {id: @package.id} + end +end + + if @normal node :normal do |lesson| {teacher_id: @normal.teacher_id} diff --git a/web/app/views/api_users/show.rabl b/web/app/views/api_users/show.rabl index 5637d0775..b141b182f 100644 --- a/web/app/views/api_users/show.rabl +++ b/web/app/views/api_users/show.rabl @@ -38,6 +38,10 @@ if current_user && @user == current_user attributes :uid, :provider, :token_expiration end + child :test_drive_package_choices do |choice| + attributes :id + end + node :geoiplocation do |user| geoiplocation = current_user.geoiplocation geoiplocation.info if geoiplocation diff --git a/web/app/views/layouts/landing.html.erb b/web/app/views/layouts/landing.html.erb index 13f816530..34eb82f5a 100644 --- a/web/app/views/layouts/landing.html.erb +++ b/web/app/views/layouts/landing.html.erb @@ -41,6 +41,8 @@ <%= render "clients/footer" %>
+ <%= render "clients/lessonSessionActions" %> + <%= render "clients/manageVsts" %> <%= render 'dialogs/dialogs' %>