3 versions of test drive available now
This commit is contained in:
parent
0d8341c2d8
commit
e46a4b01cd
|
|
@ -343,4 +343,5 @@ teacher_progression.sql
|
|||
teacher_complete.sql
|
||||
lessons.sql
|
||||
lessons_unread_messages.sql
|
||||
track_school_signups.sql
|
||||
track_school_signups.sql
|
||||
add_test_drive_types.sql
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
INSERT INTO lesson_package_types (id, name, description, package_type, price) VALUES ('test-drive-2', 'Test Drive (2)', 'Two reduced-price lessons which you can use to find that ideal teacher.', 'test-drive-2', 29.99);
|
||||
INSERT INTO lesson_package_types (id, name, description, package_type, price) VALUES ('test-drive-1', 'Test Drive (1)', 'One reduced-price lessons which you can use to find that ideal teacher.', 'test-drive-1', 15.99);
|
||||
UPDATE lesson_package_types set name = 'Test Drive (4)', package_type = 'test-drive-4' WHERE id = 'test-drive';
|
||||
ALTER TABLE users ADD COLUMN lesson_package_type_id VARCHAR(64) REFERENCES lesson_package_types(id);
|
||||
|
|
@ -18,7 +18,7 @@ TestDrive lets you take 4 full lessons (30 minutes each) from 4 different teache
|
|||
teacher for you. Finding the right teacher is the single most important determinant of success in your lessons. Would
|
||||
you marry the first person you ever dated? No? Same here. Pick 4 teachers who look great, and then see who you click
|
||||
with. It's a phenomenal value, and then you can stick with the best teacher for you.
|
||||
Click this link to sign up now for TestDrive (https://www.jamkazam.com/client#/jamclass/book-lesson/purchase_test-drive).
|
||||
Click this link to sign up now for TestDrive (https://www.jamkazam.com/client#/jamclass/test-drive-selection).
|
||||
Then you can book 4 TestDrive lessons to get rolling.
|
||||
|
||||
2. Set Up Your Gear
|
||||
|
|
|
|||
|
|
@ -410,11 +410,26 @@ module JamRuby
|
|||
self.save
|
||||
end
|
||||
|
||||
def resolved_test_drive_package
|
||||
result = nil
|
||||
purchase = student.most_recent_test_drive_purchase
|
||||
if purchase
|
||||
# for lessons already packaged
|
||||
result = purchase.lesson_package_type
|
||||
else
|
||||
# for unbooked lessons
|
||||
result = student.desired_package
|
||||
end
|
||||
if result.nil?
|
||||
result = LessonPackageType.test_drive_4
|
||||
end
|
||||
result
|
||||
end
|
||||
def lesson_package_type
|
||||
if is_single_free?
|
||||
LessonPackageType.single_free
|
||||
elsif is_test_drive?
|
||||
LessonPackageType.test_drive
|
||||
resolved_test_drive_package
|
||||
elsif is_normal?
|
||||
LessonPackageType.single
|
||||
end
|
||||
|
|
@ -451,7 +466,7 @@ module JamRuby
|
|||
if is_single_free?
|
||||
0
|
||||
elsif is_test_drive?
|
||||
LessonPackageType.test_drive.price
|
||||
resolved_test_drive_package.price
|
||||
elsif is_normal?
|
||||
teacher.teacher.booking_price(lesson_length, payment_style != PAYMENT_STYLE_MONTHLY)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ module JamRuby
|
|||
|
||||
def validate_test_drive
|
||||
if user
|
||||
if !user.can_buy_test_drive?
|
||||
if lesson_package_type.is_test_drive? && !user.can_buy_test_drive?
|
||||
errors.add(:user, "can not buy test drive right now because you have already purchased it within the last year")
|
||||
end
|
||||
end
|
||||
|
|
@ -42,7 +42,7 @@ module JamRuby
|
|||
|
||||
def add_test_drives
|
||||
if self.lesson_package_type.is_test_drive?
|
||||
new_test_drives = user.remaining_test_drives + 4
|
||||
new_test_drives = user.remaining_test_drives + lesson_package_type.test_drive_count
|
||||
User.where(id: user.id).update_all(remaining_test_drives: new_test_drives)
|
||||
user.remaining_test_drives = new_test_drives
|
||||
end
|
||||
|
|
@ -79,7 +79,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
if lesson_booking
|
||||
purchase.lesson_package_type = lesson_booking.lesson_package_type
|
||||
purchase.lesson_package_type = lesson_package_type ? lesson_package_type : lesson_booking.lesson_package_type
|
||||
purchase.price = lesson_booking.booked_price if purchase.price.nil?
|
||||
else
|
||||
purchase.lesson_package_type = lesson_package_type
|
||||
|
|
|
|||
|
|
@ -7,21 +7,29 @@ module JamRuby
|
|||
PRODUCT_TYPE = 'LessonPackageType'
|
||||
|
||||
SINGLE_FREE = 'single-free'
|
||||
TEST_DRIVE = 'test-drive'
|
||||
TEST_DRIVE_4 = 'test-drive'
|
||||
TEST_DRIVE_2 = 'test-drive-2'
|
||||
TEST_DRIVE_1 = 'test-drive-1'
|
||||
SINGLE = 'single'
|
||||
|
||||
LESSON_PACKAGE_TYPES =
|
||||
[
|
||||
SINGLE_FREE,
|
||||
TEST_DRIVE,
|
||||
TEST_DRIVE_4,
|
||||
TEST_DRIVE_2,
|
||||
TEST_DRIVE_1,
|
||||
SINGLE
|
||||
]
|
||||
|
||||
has_many :user_desired_packages, class_name: "JamRuby::User", :foreign_key => "lesson_package_type_id", inverse_of: :desired_package
|
||||
validates :name, presence: true
|
||||
validates :description, presence: true
|
||||
validates :price, presence: true
|
||||
validates :package_type, presence: true, inclusion: {in: LESSON_PACKAGE_TYPES}
|
||||
|
||||
def self.test_drive_package_ids
|
||||
[TEST_DRIVE_4, TEST_DRIVE_2, TEST_DRIVE_1]
|
||||
end
|
||||
def self.monthly
|
||||
LessonPackageType.find(MONTHLY)
|
||||
end
|
||||
|
|
@ -30,8 +38,16 @@ module JamRuby
|
|||
LessonPackageType.find(SINGLE_FREE)
|
||||
end
|
||||
|
||||
def self.test_drive
|
||||
LessonPackageType.find(TEST_DRIVE)
|
||||
def self.test_drive_4
|
||||
LessonPackageType.find(TEST_DRIVE_4)
|
||||
end
|
||||
|
||||
def self.test_drive_2
|
||||
LessonPackageType.find(TEST_DRIVE_2)
|
||||
end
|
||||
|
||||
def self.test_drive_1
|
||||
LessonPackageType.find(TEST_DRIVE_1)
|
||||
end
|
||||
|
||||
def self.single
|
||||
|
|
@ -42,17 +58,21 @@ module JamRuby
|
|||
if is_single_free?
|
||||
0
|
||||
elsif is_test_drive?
|
||||
LessonPackageType.test_drive.price
|
||||
10.00
|
||||
elsif is_normal?
|
||||
lesson_booking.booked_price #teacher.teacher.booking_price(lesson_booking.lesson_length, lesson_booking.payment_style == LessonBooking::PAYMENT_STYLE_SINGLE)
|
||||
end
|
||||
end
|
||||
|
||||
def test_drive_count
|
||||
package_type["test-drive-".length, 1].to_i
|
||||
end
|
||||
|
||||
def description(lesson_booking)
|
||||
if is_single_free?
|
||||
"Single Free Lesson"
|
||||
elsif is_test_drive?
|
||||
"Test Drive"
|
||||
"Test Drive (#{test_drive_count})"
|
||||
elsif is_normal?
|
||||
if lesson_booking.recurring
|
||||
"Recurring #{lesson_booking.payment_style == LessonBooking::PAYMENT_STYLE_WEEKLY ? "Weekly" : "Monthly"} #{lesson_booking.lesson_length}m"
|
||||
|
|
@ -71,7 +91,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def is_test_drive?
|
||||
id == TEST_DRIVE
|
||||
id.start_with?('test-drive')
|
||||
end
|
||||
|
||||
def is_normal?
|
||||
|
|
@ -86,8 +106,12 @@ module JamRuby
|
|||
def plan_code
|
||||
if package_type == SINGLE_FREE
|
||||
"lesson-package-single-free"
|
||||
elsif package_type == TEST_DRIVE
|
||||
"lesson-package-test-drive"
|
||||
elsif package_type == 'test-drive-4'
|
||||
"lesson-package-test-drive-4"
|
||||
elsif package_type == TEST_DRIVE_2
|
||||
"lesson-package-test-drive-2"
|
||||
elsif package_type == TEST_DRIVE_1
|
||||
"lesson-package-test-drive-1"
|
||||
elsif package_type == SINGLE
|
||||
"lesson-package-single"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -208,8 +208,8 @@ module JamRuby
|
|||
free && non_free
|
||||
end
|
||||
|
||||
def self.purchase_test_drive(current_user, booking = nil)
|
||||
self.purchase_lesson(current_user, booking, LessonPackageType.test_drive)
|
||||
def self.purchase_test_drive(current_user, lesson_package_type, booking = nil)
|
||||
self.purchase_lesson(current_user, booking, lesson_package_type)
|
||||
end
|
||||
|
||||
def self.purchase_normal(current_user, booking)
|
||||
|
|
@ -273,6 +273,7 @@ module JamRuby
|
|||
purchase = LessonPackagePurchase.create(current_user, lesson_booking, lesson_package_type) if purchase.nil?
|
||||
|
||||
if purchase.errors.any?
|
||||
puts "purchase errors #{purchase.errors.inspect}"
|
||||
price_info = {}
|
||||
price_info[:purchase] = purchase
|
||||
return price_info
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ module JamRuby
|
|||
has_many :user_authorizations, :class_name => "JamRuby::UserAuthorization"
|
||||
|
||||
has_many :reviews, :class_name => "JamRuby::Review"
|
||||
has_one :review_summary, :class_name => "JamRuby::ReviewSummary"
|
||||
has_one :review_summary, :class_name => "JamRuby::ReviewSummary"
|
||||
|
||||
# calendars (for scheduling NOT in music_session)
|
||||
has_many :calendars, :class_name => "JamRuby::Calendar"
|
||||
|
|
@ -71,7 +71,7 @@ module JamRuby
|
|||
has_many :band_musicians, :class_name => "JamRuby::BandMusician"
|
||||
has_many :bands, :through => :band_musicians, :class_name => "JamRuby::Band"
|
||||
has_one :teacher, :class_name => "JamRuby::Teacher"
|
||||
|
||||
|
||||
# genres
|
||||
has_many :genre_players, as: :player, class_name: "JamRuby::GenrePlayer", dependent: :destroy
|
||||
has_many :genres, through: :genre_players, class_name: "JamRuby::Genre"
|
||||
|
|
@ -176,6 +176,7 @@ 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
|
||||
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
|
||||
has_many :shopping_carts, :class_name => "JamRuby::ShoppingCart"
|
||||
|
|
@ -260,6 +261,7 @@ module JamRuby
|
|||
teacher.update_profile_pct
|
||||
end
|
||||
end
|
||||
|
||||
def user_progression_fields
|
||||
@user_progression_fields ||= Set.new ["first_downloaded_client_at", "first_ran_client_at", "first_music_session_at", "first_real_music_session_at", "first_good_music_session_at", "first_certified_gear_at", "first_invited_at", "first_friended_at", "first_recording_at", "first_social_promoted_at", "first_played_jamtrack_at"]
|
||||
end
|
||||
|
|
@ -1127,7 +1129,7 @@ module JamRuby
|
|||
user.school_id = school_id
|
||||
elsif user.is_a_teacher
|
||||
school = School.find_by_id(school_id)
|
||||
school_name = school ? school.name : 'a music school'
|
||||
school_name = school ? school.name : 'a music school'
|
||||
user.teacher = Teacher.build_teacher(user, validate_introduction: true, biography: "Teaches for #{school_name}", school_id: school_id)
|
||||
end
|
||||
else
|
||||
|
|
@ -1320,7 +1322,6 @@ module JamRuby
|
|||
end if affiliate_referral_id.present?
|
||||
|
||||
|
||||
|
||||
if user.is_a_student
|
||||
UserMailer.student_welcome_message(user).deliver
|
||||
end
|
||||
|
|
@ -1897,7 +1898,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def can_buy_test_drive?
|
||||
lesson_purchases.where(lesson_package_type_id: LessonPackageType.test_drive.id).where('created_at > ?', APP_CONFIG.test_drive_wait_period_year.years.ago).count == 0
|
||||
lesson_purchases.where('lesson_package_type_id in (?)', LessonPackageType.test_drive_package_ids).where('created_at > ?', APP_CONFIG.test_drive_wait_period_year.years.ago).count == 0
|
||||
end
|
||||
|
||||
def has_test_drives?
|
||||
|
|
@ -1946,6 +1947,7 @@ module JamRuby
|
|||
|
||||
customer
|
||||
end
|
||||
|
||||
def card_approved(token, zip, booking_id)
|
||||
|
||||
approved_booking = nil
|
||||
|
|
@ -1993,6 +1995,7 @@ module JamRuby
|
|||
normal = nil
|
||||
intent = nil
|
||||
purchase = nil
|
||||
lesson_package_type = nil
|
||||
User.transaction do
|
||||
|
||||
if params[:name].present?
|
||||
|
|
@ -2004,16 +2007,29 @@ module JamRuby
|
|||
booking = card_approved(params[:token], params[:zip], params[:booking_id])
|
||||
if params[:test_drive]
|
||||
self.reload
|
||||
result = Sale.purchase_test_drive(self, booking)
|
||||
if booking
|
||||
lesson_package_type = booking.resolved_test_drive_package
|
||||
end
|
||||
if lesson_package_type.nil?
|
||||
lesson_package_type = LessonPackageType.test_drive_4
|
||||
end
|
||||
|
||||
|
||||
result = Sale.purchase_test_drive(self, lesson_package_type, booking)
|
||||
test_drive = result[:sale]
|
||||
purchase = result[:purchase]
|
||||
|
||||
if booking && !purchase.errors.any?
|
||||
# the booking would not have a lesson_package_purchase associated yet, so let's associate it
|
||||
booking.lesson_sessions.update_all(lesson_package_purchase_id: purchase.id)
|
||||
end
|
||||
elsif params[:normal]
|
||||
self.reload
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
{lesson: booking, test_drive: test_drive, purchase: purchase}
|
||||
{lesson: booking, test_drive: test_drive, purchase: purchase, lesson_package_type: lesson_package_type}
|
||||
end
|
||||
|
||||
def requested_test_drive(teacher = nil)
|
||||
|
|
@ -2033,7 +2049,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def most_recent_test_drive_purchase
|
||||
lesson_purchases.where(lesson_package_type_id: LessonPackageType.test_drive.id).order('created_at desc').first
|
||||
lesson_purchases.where('lesson_package_type_id in (?)', [LessonPackageType.test_drive_package_ids]).order('created_at desc').first
|
||||
end
|
||||
|
||||
def test_drive_succeeded(lesson_session)
|
||||
|
|
|
|||
|
|
@ -980,7 +980,7 @@ FactoryGirl.define do
|
|||
price 30.00
|
||||
|
||||
factory :test_drive_purchase do
|
||||
lesson_package_type { JamRuby::LessonPackageType.test_drive }
|
||||
lesson_package_type { JamRuby::LessonPackageType.test_drive_4 }
|
||||
association :lesson_booking, factory: :lesson_booking
|
||||
price 49.99
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ describe "TestDrive Lesson Flow" do
|
|||
|
||||
it "works" do
|
||||
|
||||
user.desired_package = LessonPackageType.test_drive_2
|
||||
user.save!
|
||||
|
||||
# user has no test drives, no credit card on file, but attempts to book a lesson
|
||||
booking = LessonBooking.book_test_drive(user, teacher_user, valid_single_slots, "Hey I've heard of you before.")
|
||||
booking.errors.any?.should be_false
|
||||
|
|
@ -28,20 +31,24 @@ describe "TestDrive Lesson Flow" do
|
|||
booking.card_presumed_ok.should be_false
|
||||
booking.should eql user.unprocessed_test_drive
|
||||
booking.sent_notices.should be_false
|
||||
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 0
|
||||
|
||||
########## Need validate their credit card
|
||||
token = create_stripe_token
|
||||
result = user.payment_update({token: token, zip: '78759', test_drive: true})
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 3
|
||||
result = user.payment_update({token: token, zip: '78759', test_drive: true, booking_id: booking.id})
|
||||
booking = result[:lesson]
|
||||
lesson = booking.lesson_sessions[0]
|
||||
test_drive = result[:test_drive]
|
||||
booking.errors.any?.should be_false
|
||||
lesson = booking.lesson_sessions[0]
|
||||
|
||||
lesson.errors.any?.should be_false
|
||||
test_drive = result[:test_drive]
|
||||
test_drive.errors.any?.should be_false
|
||||
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 1
|
||||
|
||||
booking.card_presumed_ok.should be_true
|
||||
booking.sent_notices.should be_true
|
||||
lesson.music_session.scheduled_start.should eql booking.default_slot.scheduled_time(0)
|
||||
|
|
@ -49,20 +56,20 @@ describe "TestDrive Lesson Flow" do
|
|||
|
||||
|
||||
test_drive.stripe_charge_id.should_not be_nil
|
||||
test_drive.recurly_tax_in_cents.should be 412
|
||||
test_drive.recurly_total_in_cents.should eql 4999 + 412
|
||||
test_drive.recurly_subtotal_in_cents.should eql 4999
|
||||
test_drive.recurly_tax_in_cents.should be 247
|
||||
test_drive.recurly_total_in_cents.should eql 2999 + 247
|
||||
test_drive.recurly_subtotal_in_cents.should eql 2999
|
||||
test_drive.recurly_currency.should eql 'USD'
|
||||
line_item = test_drive.sale_line_items[0]
|
||||
line_item.quantity.should eql 1
|
||||
line_item.product_type.should eql SaleLineItem::LESSON
|
||||
line_item.product_id.should eq LessonPackageType.test_drive.id
|
||||
line_item.product_id.should eq LessonPackageType.test_drive_2.id
|
||||
user.reload
|
||||
user.stripe_customer_id.should_not be nil
|
||||
user.lesson_purchases.length.should eql 1
|
||||
user.remaining_test_drives.should eql 3
|
||||
user.remaining_test_drives.should eql 1
|
||||
lesson_purchase = user.lesson_purchases[0]
|
||||
lesson_purchase.price.should eql 49.99
|
||||
lesson_purchase.price.should eql 29.99
|
||||
lesson_purchase.lesson_package_type.is_test_drive?.should eql true
|
||||
|
||||
customer = Stripe::Customer.retrieve(user.stripe_customer_id)
|
||||
|
|
@ -173,11 +180,11 @@ describe "TestDrive Lesson Flow" do
|
|||
lesson_session.billing_error_reason.should be_nil
|
||||
lesson_session.sent_notices.should be true
|
||||
purchase = lesson_session.lesson_package_purchase
|
||||
purchase.should_not be nil
|
||||
purchase.price_in_cents.should eql 4999
|
||||
purchase.should_not be_nil
|
||||
purchase.price_in_cents.should eql 2999
|
||||
purchase.lesson_package_type.is_test_drive?.should be true
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 3
|
||||
user.remaining_test_drives.should eql 1
|
||||
UserMailer.deliveries.length.should eql 2 # one for student, one for teacher
|
||||
|
||||
teacher_distribution = lesson_session.teacher_distribution
|
||||
|
|
|
|||
|
|
@ -731,7 +731,7 @@ describe Sale do
|
|||
line_item = sale.sale_line_items[0]
|
||||
line_item.quantity.should eql 1
|
||||
line_item.product_type.should eql SaleLineItem::LESSON
|
||||
line_item.product_id.should eq LessonPackageType.test_drive.id
|
||||
line_item.product_id.should eq LessonPackageType.test_drive_4.id
|
||||
|
||||
user.reload
|
||||
user.stripe_customer_id.should_not be nil
|
||||
|
|
@ -778,7 +778,7 @@ describe Sale do
|
|||
line_item = sale.sale_line_items[0]
|
||||
line_item.quantity.should eql 1
|
||||
line_item.product_type.should eql SaleLineItem::LESSON
|
||||
line_item.product_id.should eq LessonPackageType.test_drive.id
|
||||
line_item.product_id.should eq LessonPackageType.test_drive_4.id
|
||||
|
||||
|
||||
user.reload
|
||||
|
|
@ -819,7 +819,7 @@ describe Sale do
|
|||
line_item = sale.sale_line_items[0]
|
||||
line_item.quantity.should eql 1
|
||||
line_item.product_type.should eql SaleLineItem::LESSON
|
||||
line_item.product_id.should eq LessonPackageType.test_drive.id
|
||||
line_item.product_id.should eq LessonPackageType.test_drive_4.id
|
||||
end
|
||||
|
||||
it "will reject second test drive purchase" do
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ def testdrive_lesson(user, teacher, slots = nil)
|
|||
booking.card_presumed_ok.should be_true
|
||||
|
||||
if user.most_recent_test_drive_purchase.nil?
|
||||
LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive)
|
||||
LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive_4)
|
||||
end
|
||||
|
||||
lesson.accept({message: 'Yeah I got this', slot: slots[0]})
|
||||
|
|
@ -66,7 +66,7 @@ def normal_lesson(user, teacher, slots = nil)
|
|||
booking.card_presumed_ok.should be_true
|
||||
|
||||
#if user.most_recent_test_drive_purchase.nil?
|
||||
# LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive)
|
||||
# LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive_4)
|
||||
#end
|
||||
|
||||
lesson.accept({message: 'Yeah I got this', slot: slots[0]})
|
||||
|
|
|
|||
|
|
@ -161,21 +161,37 @@
|
|||
return context.JK.prodBubble($element, 'teacher-profile', {}, bigHelpDarkOptions({spikeGirth:0, spikeLength: 0, duration:10000, offsetParent:$offsetParent, width:385, positions:['top', 'right', 'bottom']}))
|
||||
}
|
||||
|
||||
helpBubble.showUseRemainingTestDrives = function($element, $offsetParent) {
|
||||
return context.JK.onceBubble($element, 'side-remaining-test-drives', {}, {offsetParent:$offsetParent, width:260, positions:['right'], postShow: function(container) {
|
||||
helpBubble.showUseRemainingTestDrives = function($element, $offsetParent, user, callback) {
|
||||
return context.JK.onceBubble($element, 'side-remaining-test-drives', user, {offsetParent:$offsetParent, width:260, positions:['right'], postShow: function(container) {
|
||||
|
||||
var $bookNow = $('a.book-now')
|
||||
$bookNow.off('click').on('click', function(e) {
|
||||
e.preventDefault()
|
||||
callback()
|
||||
return false;
|
||||
})
|
||||
}})
|
||||
}
|
||||
|
||||
helpBubble.showBuyTestDrive = function($element, $offsetParent) {
|
||||
return context.JK.onceBubble($element, 'side-buy-test-drive', {}, {offsetParent:$offsetParent, width:260, positions:['right'], postShow: function(container) {
|
||||
|
||||
helpBubble.showBuyTestDrive = function($element, $offsetParent, user, callback) {
|
||||
return context.JK.onceBubble($element, 'side-buy-test-drive', user, {offsetParent:$offsetParent, width:260, positions:['right'], postShow: function(container) {
|
||||
var $bookNow = $('a.book-now')
|
||||
$bookNow.off('click').on('click', function(e) {
|
||||
e.preventDefault()
|
||||
callback()
|
||||
return false;
|
||||
})
|
||||
}})
|
||||
}
|
||||
|
||||
helpBubble.showBuyNormalLesson = function($element, $offsetParent) {
|
||||
return context.JK.onceBubble($element, 'side-buy-normal-lesson', {}, {offsetParent:$offsetParent, width:260, positions:['right'], postShow: function(container) {
|
||||
|
||||
helpBubble.showBuyNormalLesson = function($element, $offsetParent, user, callback) {
|
||||
return context.JK.onceBubble($element, 'side-buy-normal-lesson', user, {offsetParent:$offsetParent, width:260, positions:['right'], postShow: function(container) {
|
||||
var $bookNow = $('a.book-now')
|
||||
$bookNow.off('click').on('click', function(e) {
|
||||
e.preventDefault()
|
||||
callback()
|
||||
return false;
|
||||
})
|
||||
}})
|
||||
}
|
||||
})(window, jQuery);
|
||||
|
|
@ -62,7 +62,7 @@ UserStore = context.UserStore
|
|||
@state.type == 'normal'
|
||||
|
||||
isTestDrive: () ->
|
||||
@state.type == 'test-drive'
|
||||
@state.type?.indexOf('test-drive') == 0
|
||||
|
||||
parseId:(id) ->
|
||||
if !id?
|
||||
|
|
@ -79,7 +79,6 @@ UserStore = context.UserStore
|
|||
@resetErrors()
|
||||
|
||||
beforeShow: (e) ->
|
||||
logger.debug("BookLesson: beforeShow", e.id)
|
||||
|
||||
afterShow: (e) ->
|
||||
logger.debug("BookLesson: afterShow", e.id)
|
||||
|
|
@ -268,9 +267,6 @@ UserStore = context.UserStore
|
|||
onCancel: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
isTestDrive: () ->
|
||||
@state.type == 'test-drive'
|
||||
|
||||
isNormal: () ->
|
||||
@state.type == 'normal'
|
||||
|
||||
|
|
@ -314,11 +310,12 @@ UserStore = context.UserStore
|
|||
results
|
||||
|
||||
render: () ->
|
||||
teacher = @state.teacher
|
||||
|
||||
photo_url = teacher?.photo_url
|
||||
if !photo_url?
|
||||
photo_url = '/assets/shared/avatar_generic.png'
|
||||
|
||||
teacher = @state.teacher
|
||||
|
||||
if teacher?
|
||||
name = `<div className="teacher-name">{teacher.name}</div>`
|
||||
|
|
@ -446,6 +443,39 @@ UserStore = context.UserStore
|
|||
<a className={bookLessonClasses} onClick={this.onBookLesson}>BOOK TESTDRIVE LESSON</a>
|
||||
</div>`
|
||||
|
||||
testDriveCredits = 1
|
||||
|
||||
if this.state.user.lesson_package_type_id == 'test-drive'
|
||||
testDriveCredits = 4
|
||||
else if this.state.user.lesson_package_type_id == 'test-drive-1'
|
||||
testDriveCredits = 1
|
||||
else if this.state.user.lesson_package_type_id == 'test-drive-2'
|
||||
testDriveCredits = 2
|
||||
|
||||
if this.state.user.remaining_test_drives > 0
|
||||
testDriveBookingInfo = `<div className="booking-info">
|
||||
|
||||
<p>You are booking a single 30-minute TestDrive session.</p>
|
||||
|
||||
<p>You currently have {testDriveLessons} available. If you need to cancel, you must cancel at least 24 hours before the lesson is scheduled to start, or you will be charged 1 TestDrive lesson credit.<br/>
|
||||
|
||||
<div className="jamclass-policies"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass
|
||||
policies</a></div>
|
||||
</p>
|
||||
</div>`
|
||||
else
|
||||
testDriveBookingInfo = `<div className="booking-info">
|
||||
|
||||
<p>You are booking a single 30-minute TestDrive session.</p>
|
||||
|
||||
<p>Once payment is entered on the next screen, the teacher will be notified, and this lesson will then use 1 of {testDriveCredits} TestDrive credits. If you need to cancel, you must cancel at least 24 hours before the lesson is scheduled to start, or you will be charged 1 TestDrive lesson credit.<br/>
|
||||
|
||||
<div className="jamclass-policies"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass
|
||||
policies</a></div>
|
||||
</p>
|
||||
</div>`
|
||||
|
||||
|
||||
columnLeft = `<div className="column column-left">
|
||||
{header}
|
||||
{slots}
|
||||
|
|
@ -468,15 +498,7 @@ UserStore = context.UserStore
|
|||
</div>
|
||||
{name}
|
||||
</div>
|
||||
<div className="booking-info">
|
||||
<p>You are purchasing a single 30-minute TestDrive session.</p>
|
||||
|
||||
<p>You currently have {testDriveLessons} available. If you need to cancel, you must cancel at least 24 hours before the lesson is scheduled to start, or you will be charged 1 TestDrive lesson credit.<br/>
|
||||
|
||||
<div className="jamclass-policies"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass
|
||||
policies</a></div>
|
||||
</p>
|
||||
</div>
|
||||
{testDriveBookingInfo}
|
||||
</div>`
|
||||
|
||||
else if @isNormal()
|
||||
|
|
|
|||
|
|
@ -272,29 +272,58 @@ UserStore = context.UserStore
|
|||
window.UserActions.refresh()
|
||||
|
||||
# if the response has a lesson, take them there
|
||||
if response.lesson?.id?
|
||||
if response.test_drive?
|
||||
# ok, they bought a package
|
||||
if response.lesson_package_type?
|
||||
# always of form test-drive-#
|
||||
prefixLength = "test-drive-".length
|
||||
packageLength = response.lesson_package_type.package_type.length
|
||||
|
||||
logger.debug("prefix: " + prefixLength.toString())
|
||||
logger.debug("package: " + packageLength.toString())
|
||||
testDriveCount = response.lesson_package_type.package_type.substring(prefixLength, packageLength)
|
||||
|
||||
logger.debug("testDriveCount: " + testDriveCount)
|
||||
|
||||
if response.test_drive?.teacher_id
|
||||
teacher_id = response.test_drive.teacher_id
|
||||
if testDriveCount == 1
|
||||
text = "You have purchased a 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
|
||||
text = "You have purchased #{testDriveCount} TestDrive credits and have used 1 credit it to request a JamClass with #{@state.teacher.name}. The teacher has received your request and should respond shortly."
|
||||
location = "/client#/jamclass"
|
||||
else
|
||||
if @state.teacher?.id
|
||||
|
||||
# the user bought the testdrive, and there is a teacher of interest in context (but no booking)
|
||||
if testDriveCount == 1
|
||||
text = "You now have 1 TestDrive credit.<br/><br/>We've taken you to the lesson booking screen for the teacher you initially showed interest in."
|
||||
location = "/client#/jamclass/book-lesson/test-drive_" + teacher_id
|
||||
else
|
||||
text = "You now have #{testDriveCount} TestDrive credits that you can take with #{testDriveCount} different teachers.<br/><br/>We've taken you to the lesson booking screen for the teacher you initially showed interest in."
|
||||
location = "/client#/jamclass/book-lesson/test-drive_" + teacher_id
|
||||
else
|
||||
# the user bought test drive, but 'cold' , i.e., no teacher in context
|
||||
if testDriveCount == 1
|
||||
text = "You now have 1 TestDrive credit.<br/><br/>We've taken you to the Teacher Search screen, so you can search for teachers right for you."
|
||||
location = "/client#/teachers/search"
|
||||
else
|
||||
text = "You now have #{testDriveCount} TestDrive credits that you can take with #{testDriveCount} different teachers.<br/><br/>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)
|
||||
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")
|
||||
window.location = "/client#/jamclass/"
|
||||
|
||||
else if response.lesson?.id?
|
||||
context.JK.Banner.showNotice("Lesson Requested","The teacher has been notified of your lesson request, and should respond soon.<br/><br/>We've taken you automatically to the page for this request, and sent an email to you with a link here as well. All communication with the teacher will show up on this page and in email.")
|
||||
|
||||
url = "/client#/jamclass/lesson-booking/" + response.lesson.id
|
||||
url = "/client#/jamclass"
|
||||
window.location.href = url
|
||||
|
||||
else if response.test_drive?
|
||||
|
||||
if response.test_drive?.teacher_id
|
||||
teacher_id = response.test_drive.teacher_id
|
||||
else if @state.teacher?.id
|
||||
teacher_id = @state.teacher.id
|
||||
|
||||
if teacher_id?
|
||||
text = "You now have 4 lessons that you can take with 4 different teachers.<br/><br/>We've taken you automatically to the lesson booking screen for the teacher you initially showed interest in."
|
||||
location = "/client#/profile/teacher/" + teacher_id
|
||||
location = "/client#/jamclass/book-lesson/test-drive_" + teacher_id
|
||||
else
|
||||
text = "You now have 4 lessons that you can take with 4 different teachers.<br/><br/>We've taken you automatically 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)
|
||||
window.location = location
|
||||
else
|
||||
window.location = "/client#/teachers/search"
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ proficiencyDescriptionMap = {
|
|||
@TeacherProfile = React.createClass({
|
||||
|
||||
mixins: [
|
||||
PostProcessorMixin,
|
||||
Reflux.listenTo(AppStore, "onAppInit"),
|
||||
Reflux.listenTo(UserStore, "onUserChanged"),
|
||||
Reflux.listenTo(SubjectStore, "onSubjectsChanged"),
|
||||
|
|
@ -89,12 +90,18 @@ proficiencyDescriptionMap = {
|
|||
|
||||
userDetailDone: (response) ->
|
||||
if response.id == @state.userId
|
||||
console.log("teacher markup", response)
|
||||
@postProcessUser(response)
|
||||
@setState({user: response, isSelf: response.id == context.JK.currentUserId})
|
||||
else
|
||||
logger.debug("ignoring userDetailDone", response.id, @state.userId)
|
||||
|
||||
if @visible
|
||||
@showSideBubble()
|
||||
@showSideBubbleWhenReady()
|
||||
|
||||
showSideBubbleWhenReady: () ->
|
||||
if @user? && @state.user?
|
||||
if @visible
|
||||
@showSideBubble()
|
||||
|
||||
beforeHide: (e) ->
|
||||
@visible = false
|
||||
|
|
@ -130,18 +137,22 @@ proficiencyDescriptionMap = {
|
|||
@screen.btOff()
|
||||
|
||||
showUseRemainingTestDrivesBubble: ( ) ->
|
||||
console.log("Ok showUseRemainingTestDrivesBubble")
|
||||
context.JK.HelpBubbleHelper.showUseRemainingTestDrives(@screen, @screen)
|
||||
context.JK.HelpBubbleHelper.showUseRemainingTestDrives(@screen, @screen, @user, (() => @useRemainingTestDrives()))
|
||||
|
||||
showBuyTestDriveBubble: () ->
|
||||
console.log("ok showBuyTestDriveBubble")
|
||||
context.JK.HelpBubbleHelper.showBuyTestDrive(@screen, @screen)
|
||||
context.JK.HelpBubbleHelper.showBuyTestDrive(@screen, @screen, @user, (() => @buyTestDrive()))
|
||||
|
||||
showBuyNormalLessonBubble: () ->
|
||||
console.log("OK showBuyNormalLessonBubble")
|
||||
context.JK.HelpBubbleHelper.showBuyNormalLesson(@screen, @screen)
|
||||
context.JK.HelpBubbleHelper.showBuyNormalLesson(@screen, @screen, @state.user, (() => @buyNormalLesson()))
|
||||
|
||||
useRemainingTestDrives: () ->
|
||||
window.location.href = "/client#/jamclass/book-lesson/test-drive_#{@state.user.id}"
|
||||
buyTestDrive: () ->
|
||||
window.location.href = "/client#/jamclass/test-drive-selection/#{@state.user.id}"
|
||||
|
||||
|
||||
buyNormalLesson: () ->
|
||||
window.location.href = "/client#/jamclass/book-lesson/normal_#{@state.user.id}"
|
||||
|
||||
getInitialState: () ->
|
||||
{
|
||||
|
|
@ -157,6 +168,7 @@ proficiencyDescriptionMap = {
|
|||
|
||||
onUserChanged: (userState) ->
|
||||
@user = userState?.user
|
||||
@showSideBubbleWhenReady()
|
||||
|
||||
editProfile: (selected, e) ->
|
||||
e.preventDefault()
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ ProfileActions = @ProfileActions
|
|||
refreshing: false
|
||||
|
||||
getInitialState: () ->
|
||||
{searchOptions: {}, results: []}
|
||||
{searchOptions: {}, results: [], user: null}
|
||||
|
||||
onAppInit: (@app) ->
|
||||
@app.bindScreen('teachers/search', {beforeShow: @beforeShow, afterShow: @afterShow, afterHide: @afterHide})
|
||||
|
|
@ -59,6 +59,7 @@ ProfileActions = @ProfileActions
|
|||
@setState(results)
|
||||
|
||||
onUserChanged: (@user) ->
|
||||
@setState({user: @user?.user})
|
||||
|
||||
#onTeacherSearchChanged: (options) ->
|
||||
# if @visible
|
||||
|
|
@ -119,7 +120,8 @@ ProfileActions = @ProfileActions
|
|||
.done((response) =>
|
||||
if response.remaining_test_drives == 0 && response['can_buy_test_drive?']
|
||||
logger.debug("TeacherSearchScreen: user offered test drive")
|
||||
@app.layout.showDialog('try-test-drive', {d1: user.teacher.id})
|
||||
#@app.layout.showDialog('try-test-drive', {d1: user.teacher.id})
|
||||
window.location.href = '/client#/jamclass/test-drive-selection/' + user.id
|
||||
else if response.remaining_test_drives > 0
|
||||
if response.booked_with_teacher && !context.JK.currentUserAdmin
|
||||
logger.debug("TeacherSearchScreen: teacher already test-drived")
|
||||
|
|
@ -130,6 +132,7 @@ ProfileActions = @ProfileActions
|
|||
logger.debug("TeacherSearchScreen: user being sent to book a lesson")
|
||||
|
||||
window.location.href = '/client#/jamclass/book-lesson/test-drive_' + user.id
|
||||
#window.location.href = '/client#/jamclass/test-drive-selection/' + user.id
|
||||
else
|
||||
# user has no remaining test drives and can't buy any
|
||||
logger.debug("TeacherSearchScreen: test drive all done")
|
||||
|
|
@ -230,6 +233,11 @@ ProfileActions = @ProfileActions
|
|||
if !bio?
|
||||
bio = 'No bio'
|
||||
|
||||
console.log("@state.sur : #{@state.user.remaining_test_drives}, #{@state.user['can_buy_test_drive?']}")
|
||||
if !@state.user? || @state.user.remaining_test_drives > 0 || @state.user['can_buy_test_drive?']
|
||||
bookTestDriveBtn = `<a className="button-orange try-test-drive" onClick={this.bookTestDrive.bind(this, user)}>BOOK TESTDRIVE LESSON</a>`
|
||||
else
|
||||
bookSingleBtn = `<a className="button-orange try-normal" onClick={this.bookNormalLesson.bind(this, user)}>BOOK LESSON</a>`
|
||||
resultsJsx.push(`<div key={user.id} className="teacher-search-result" data-teacher-id={user.id}>
|
||||
<div className="user-avatar">
|
||||
<div className="avatar small">
|
||||
|
|
@ -246,8 +254,8 @@ ProfileActions = @ProfileActions
|
|||
</div>
|
||||
<div className="teacher-actions">
|
||||
<a className="button-orange more-about-teacher" onClick={this.moreAboutTeacher.bind(this, user)}>MORE ABOUT THIS TEACHER</a>
|
||||
<a className="button-orange try-test-drive" onClick={this.bookTestDrive.bind(this, user)}>BOOK TESTDRIVE LESSON</a>
|
||||
<a className="button-orange try-normal" onClick={this.bookNormalLesson.bind(this, user)}>BOOK NORMAL LESSON</a>
|
||||
{bookTestDriveBtn}
|
||||
{bookSingleBtn}
|
||||
</div>
|
||||
</div>
|
||||
<br className="clearall" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
context = window
|
||||
rest = context.JK.Rest()
|
||||
logger = context.JK.logger
|
||||
|
||||
UserStore = context.UserStore
|
||||
|
||||
@TestDriveSelection = React.createClass({
|
||||
|
||||
mixins: [
|
||||
Reflux.listenTo(AppStore, "onAppInit"),
|
||||
Reflux.listenTo(UserStore, "onUserChanged")
|
||||
]
|
||||
|
||||
onAppInit: (@app) ->
|
||||
@app.bindScreen('jamclass/test-drive-selection',
|
||||
{afterShow: @afterShow, beforeHide: @beforeHide, navName: 'TestDrive Selection'})
|
||||
|
||||
onUserChanged: (userState) ->
|
||||
@setState({user: userState?.user})
|
||||
|
||||
beforeHide: (e) ->
|
||||
|
||||
|
||||
afterShow: (e) ->
|
||||
logger.debug("TestDriveSelection: afterShow", e.id)
|
||||
|
||||
parsed = @parseId(e.id)
|
||||
|
||||
id = parsed.id
|
||||
|
||||
if id? && id != 'none' && id != 'default'
|
||||
@setState({teacherId: id, teacher: null})
|
||||
else
|
||||
@setState({teacherId: null, teacher: null})
|
||||
|
||||
rest.getUserDetail({
|
||||
id: id,
|
||||
show_teacher: true
|
||||
}).done((response) => @userDetailDone(response)).fail(@app.ajaxError)
|
||||
|
||||
parseId: (id) ->
|
||||
if !id?
|
||||
{id: null}
|
||||
else
|
||||
{id: id}
|
||||
|
||||
userDetailDone: (response) ->
|
||||
if response.id == @state.teacherId
|
||||
@setState({teacher: response, isSelf: response.id == context.JK.currentUserId})
|
||||
else
|
||||
logger.debug("TestDriveSelection: ignoring teacher details", response.id, @state.teacherId)
|
||||
|
||||
getInitialState: () ->
|
||||
{
|
||||
user: null,
|
||||
teacher: null,
|
||||
teacherId: null,
|
||||
}
|
||||
|
||||
packageSelect: (packageType, e) ->
|
||||
e.preventDefault()
|
||||
|
||||
console.log("test-drive-#{packageType}")
|
||||
rest.updateUser({desired_package: "test-drive-#{packageType}"}).done((response) => @packageSelectedDone(response)).fail((jqXHR) => @packageSelectedFail(jqXHR))
|
||||
|
||||
|
||||
packageSelectedFail: (jqXHR) ->
|
||||
console.log("package selected fail: " + jqXHR.responseText)
|
||||
@app.ajaxError(jqXHR)
|
||||
|
||||
packageSelectedDone:(response) ->
|
||||
|
||||
url = "/client#/jamclass/book-lesson/test-drive"
|
||||
|
||||
console.log("TEACHER", JSON.stringify(@state.teacher))
|
||||
if @state.teacher?
|
||||
url += '_' + @state.teacher.id
|
||||
else
|
||||
url = "/client#/jamclass/lesson-payment/test-drive"
|
||||
|
||||
window.location.href = url
|
||||
|
||||
avatar: (name = 'your choice', photo_url = '/assets/shared/avatar_generic.png') ->
|
||||
`<div className="avatar-header">
|
||||
<div className="avatar">
|
||||
<img src={photo_url}/>
|
||||
</div>
|
||||
</div>`
|
||||
render: () ->
|
||||
teacher_name = @state.teacher?.name
|
||||
photo_url = @state.teacher?.photo_url
|
||||
if !photo_url?
|
||||
photo_url = '/assets/shared/avatar_generic.png'
|
||||
|
||||
`<div className="content-body-scroller">
|
||||
<Nav/>
|
||||
|
||||
<div className="selection-area">
|
||||
<div className="test-drive-selection-wrapper select-4">
|
||||
<div className="test-drive-selection">
|
||||
<div className="td-header">MOST POPULAR</div>
|
||||
<div className="td-content">
|
||||
<div className="avatars">
|
||||
{this.avatar(teacher_name, photo_url)}
|
||||
{this.avatar()}
|
||||
{this.avatar()}
|
||||
{this.avatar()}
|
||||
</div>
|
||||
<div className="td-msg">
|
||||
GET 4 LESSONS WITH 4 DIFFERENT TEACHERS FOR JUST $12.50 EACH
|
||||
</div>
|
||||
<div className="td-desc">
|
||||
You wouldn't marry the first person you date - right? Choosing the right teacher is the most important
|
||||
thing you can do to ensure success and become a better musician. Try 4 different teachers. Then pick the
|
||||
one
|
||||
who is best for YOU!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a className="button-orange select-4 select-package" onClick={this.packageSelect.bind(this, '4')}>SELECT</a>
|
||||
|
||||
<div className="price-notice">Just $49.99!</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="test-drive-selection-wrapper select-2">
|
||||
<div className="test-drive-selection">
|
||||
<div className="td-header">GREAT VALUE</div>
|
||||
<div className="td-content">
|
||||
<div className="avatars">
|
||||
{this.avatar(teacher_name, photo_url)}
|
||||
{this.avatar()}
|
||||
</div>
|
||||
<div className="td-msg">
|
||||
GET 2 LESSONS<br/>FOR THE PRICE OF 1
|
||||
</div>
|
||||
<div className="td-desc">
|
||||
Want to try more than one teacher, but 4 is too many for you? Try two lessons with two different
|
||||
teachers for the price of one lesson.
|
||||
A great value, and a good way to find an excellent teacher!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a className="button-orange select-2 select-package" onClick={this.packageSelect.bind(this, '2')}>SELECT</a>
|
||||
|
||||
<div className="price-notice">Just $29.99!</div>
|
||||
</div>
|
||||
|
||||
<div className="test-drive-selection-wrapper select-1">
|
||||
<div className="test-drive-selection">
|
||||
<div className="td-header">I'M SURE</div>
|
||||
<div className="td-content">
|
||||
<div className="avatars">
|
||||
{this.avatar(teacher_name, photo_url)}
|
||||
</div>
|
||||
<div className="td-msg">
|
||||
GET 1 HALF-PRICE LESSON<br/>TO GET STARTED
|
||||
</div>
|
||||
<div className="td-desc">
|
||||
Are you confident you've found the best teacher for you? Then book your first lesson at a terrific
|
||||
value, and get your first lesson scheduled to start learning more today!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<a className="button-orange select-1 select-package" onClick={this.packageSelect.bind(this, '1')}>SELECT</a>
|
||||
|
||||
<div className="price-notice">Just $14.99!</div>
|
||||
</div>
|
||||
<br className="clearall"/>
|
||||
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
|
|
@ -19,7 +19,6 @@ teacherActions = window.JK.Actions.Teacher
|
|||
lesson.isAdmin = context.JK.currentUserAdmin
|
||||
lesson.cardNotOk = !lesson.lesson_booking.card_presumed_ok
|
||||
|
||||
console.log("lesson.isAdmin",lesson.isAdmin )
|
||||
if (lesson.status == 'requested' || lesson.status == 'countered')
|
||||
lesson.isRequested = true
|
||||
if lesson.cardNotOk
|
||||
|
|
@ -56,4 +55,40 @@ teacherActions = window.JK.Actions.Teacher
|
|||
user.musician_profile = '/client#/profile/' + user.id
|
||||
user.best_profile = user.musician_profile
|
||||
|
||||
if user.is_a_teacher
|
||||
cheapest_lesson_stmt = '(no pricing set yet)'
|
||||
lowestPrice = null
|
||||
lowestDuration = null
|
||||
single = true
|
||||
enabledMinutes = []
|
||||
for minutes in [30, 45, 60, 90, 120]
|
||||
duration_enabled = user.teacher["lesson_duration_#{minutes}"]
|
||||
|
||||
if duration_enabled
|
||||
enabledMinutes.push(minutes)
|
||||
if user.teacher.prices_per_lesson
|
||||
for minutes in enabledMinutes
|
||||
lesson_price = user.teacher["price_per_lesson_#{minutes}_cents"]
|
||||
if lesson_price?
|
||||
if !lowestPrice? || lesson_price < lowestPrice
|
||||
lowestPrice = lesson_price
|
||||
single = true
|
||||
lowestDuration = minutes
|
||||
for minutes in enabledMinutes
|
||||
lesson_price = user.teacher["price_per_month_#{minutes}_cents"]
|
||||
if lesson_price?
|
||||
if !lowestPrice? || (lesson_price / 4) < lowestPrice
|
||||
lowestPrice = lesson_price / 4
|
||||
single = false
|
||||
lowestDuration = minutes
|
||||
|
||||
if lowestPrice?
|
||||
if single
|
||||
# lowest price appears to be a single lesson
|
||||
cheapest_lesson_stmt = "$#{lowestPrice / 100} for #{lowestDuration} minutes"
|
||||
else
|
||||
# lowest price appears to be a monthly recurring lesson
|
||||
cheapest_lesson_stmt = "$#{Math.round(lowestPrice * 4) / 100} per month"
|
||||
|
||||
user.cheapest_lesson_stmt = cheapest_lesson_stmt
|
||||
}
|
||||
|
|
@ -143,8 +143,13 @@
|
|||
options = {};
|
||||
}
|
||||
|
||||
var originalPostShow = options.postShow;
|
||||
options.postShow = function(container) {
|
||||
context.JK.popExternalLinks($(container))
|
||||
|
||||
if (originalPostShow) {
|
||||
originalPostShow(container);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -64,22 +64,6 @@ $labelFontSize: 12px;
|
|||
}
|
||||
|
||||
|
||||
select {
|
||||
|
||||
border: 0 !important; /*Removes border*/
|
||||
-webkit-appearance: none; /*Removes default chrome and safari style*/
|
||||
-moz-appearance: none; /* Removes Default Firefox style*/
|
||||
appearance: none;
|
||||
background: url('/assets/down_arrow_black_pad.png') no-repeat; /*Adds background-image*/
|
||||
background-position: right center; /*Position of the background-image*/
|
||||
text-indent: 0.01px; /* Removes default arrow from firefox*/
|
||||
text-overflow: ""; /*Removes default arrow from firefox*/
|
||||
cursor: pointer;
|
||||
padding-right:20px;
|
||||
&::-ms-expand {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@mixin border_box_sizing {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ body.jam, body.web, .dialog{
|
|||
}
|
||||
p {
|
||||
margin:.8em 1em;
|
||||
line-height:120%;
|
||||
}
|
||||
.book-now {
|
||||
width:100px;
|
||||
|
|
|
|||
|
|
@ -76,8 +76,21 @@ a.arrow-down {
|
|||
}
|
||||
|
||||
select {
|
||||
padding:3px;
|
||||
font-size:15px;
|
||||
|
||||
border: 0 !important; /*Removes border*/
|
||||
-webkit-appearance: none; /*Removes default chrome and safari style*/
|
||||
-moz-appearance: none; /* Removes Default Firefox style*/
|
||||
appearance: none;
|
||||
background: #C5C5C5 url('/assets/down_arrow_black_pad.png') no-repeat; /*Adds background-image*/
|
||||
background-position: right center; /*Position of the background-image*/
|
||||
text-indent: 0.01px; /* Removes default arrow from firefox*/
|
||||
text-overflow: ""; /*Removes default arrow from firefox*/
|
||||
cursor: pointer;
|
||||
padding:3px 20px 3px 3px;
|
||||
&::-ms-expand {
|
||||
display: none;
|
||||
}
|
||||
font-size:15px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,20 @@
|
|||
.column-left {
|
||||
float:left;
|
||||
padding-right:20px;
|
||||
|
||||
.slot.slot-2 {
|
||||
border-style: solid;
|
||||
border-width: 1px 0 0 0;
|
||||
border-color: #cccccc;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.description {
|
||||
border-style: solid;
|
||||
border-width: 1px 0 0 0;
|
||||
border-color: #cccccc;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
.column-right {
|
||||
float:right;
|
||||
|
|
@ -56,7 +70,7 @@
|
|||
textarea {
|
||||
width:100%;
|
||||
@include border_box_sizing;
|
||||
height:125px;
|
||||
height:75px;
|
||||
}
|
||||
.field {
|
||||
display:inline-block;
|
||||
|
|
@ -99,7 +113,7 @@
|
|||
}
|
||||
.jamclass-policies {
|
||||
text-align:center;
|
||||
margin-top:-20px;
|
||||
margin-top:-10px;
|
||||
}
|
||||
.actions {
|
||||
margin-left:-3px;
|
||||
|
|
@ -138,7 +152,7 @@
|
|||
width:80%;
|
||||
}
|
||||
}
|
||||
select.hour {
|
||||
margin-left:20px;
|
||||
select.am_pm {
|
||||
margin-left:13px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,164 @@
|
|||
@import "client/common";
|
||||
|
||||
|
||||
$fluid-break: 1335px;
|
||||
@mixin layout-small {
|
||||
@media (max-width: #{$fluid-break - 1px}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin layout-normal {
|
||||
@media (min-width: #{$fluid-break}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#test-drive-selection {
|
||||
|
||||
|
||||
|
||||
div[data-react-class="TestDriveSelection"] {
|
||||
height: 100%;
|
||||
}
|
||||
.content-body-scroller {
|
||||
height: 100%;
|
||||
padding: 30px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 20px !important;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.test-drive-selection-wrapper {
|
||||
float:left;
|
||||
text-align:center;
|
||||
width:31%;
|
||||
|
||||
&.select-4 {
|
||||
|
||||
}
|
||||
&.select-2 {
|
||||
margin:0 3.5%;
|
||||
}
|
||||
&.select-1 {
|
||||
|
||||
}
|
||||
}
|
||||
.test-drive-selection {
|
||||
display:inline-block;
|
||||
border-radius:10px;
|
||||
border-width:1px;
|
||||
border-color:$ColorScreenPrimary;
|
||||
border-style:solid;
|
||||
margin-bottom:15px;
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
min-height:360px;
|
||||
}
|
||||
@media (min-width: 1181px) {
|
||||
min-height:340px;
|
||||
}
|
||||
@media (min-width: 1450px) {
|
||||
min-height:305px;
|
||||
}
|
||||
}
|
||||
|
||||
a.select-package {
|
||||
margin-bottom:15px;
|
||||
max-width: 140px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.price-notice {
|
||||
color:white;
|
||||
font-size:16px;
|
||||
}
|
||||
|
||||
.td-header {
|
||||
height:45px;
|
||||
color:white;
|
||||
text-align:center;
|
||||
font-size:24px;
|
||||
line-height: 45px;
|
||||
vertical-align: middle;
|
||||
background-color:$ColorScreenPrimary;
|
||||
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
|
||||
@media (max-width: 1130px) {
|
||||
font-size:16px;
|
||||
}
|
||||
}
|
||||
.td-content {
|
||||
@include border-box_sizing;
|
||||
padding:10px;
|
||||
width:100%;
|
||||
|
||||
}
|
||||
|
||||
.avatars {
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.td-msg {
|
||||
margin-bottom:20px;
|
||||
|
||||
@media (max-width: 1400px) {
|
||||
min-height:42px;
|
||||
}
|
||||
}
|
||||
.td-desc {
|
||||
line-height:120%;
|
||||
color:$ColorTextTypical;
|
||||
}
|
||||
|
||||
.avatar-header {
|
||||
display:inline-block;
|
||||
}
|
||||
.avatar {
|
||||
display:inline-block;
|
||||
padding:1px;
|
||||
width:48px;
|
||||
height:48px;
|
||||
background-color:#ed4818;
|
||||
margin:10px 8px 0 0;
|
||||
-webkit-border-radius:24px;
|
||||
-moz-border-radius:24px;
|
||||
border-radius:24px;
|
||||
float:none;
|
||||
|
||||
@include layout-small {
|
||||
width:32px;
|
||||
height:32px;
|
||||
-webkit-border-radius:16px;
|
||||
-moz-border-radius:16px;
|
||||
border-radius:16px;
|
||||
margin:10px 6px 0 0;
|
||||
}
|
||||
}
|
||||
.avatar img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
-webkit-border-radius:24px;
|
||||
-moz-border-radius:24px;
|
||||
border-radius:24px;
|
||||
@include layout-small {
|
||||
width:32px;
|
||||
height:32px;
|
||||
-webkit-border-radius:16px;
|
||||
-moz-border-radius:16px;
|
||||
border-radius:16px;
|
||||
}
|
||||
}
|
||||
.selection-area {
|
||||
width:100%;
|
||||
padding-top:20px;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ class ApiStripeController < ApiController
|
|||
@lesson = data[:lesson]
|
||||
@test_drive = data[:test_drive]
|
||||
@normal = data[:normal]
|
||||
@lesson_package_type = data[:lesson_package_type]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
require 'sanitize'
|
||||
class
|
||||
ApiUsersController < ApiController
|
||||
class ApiUsersController < ApiController
|
||||
|
||||
before_filter :api_signed_in_user, :except => [:create, :calendar, :show, :signup_confirm, :auth_session_create, :complete, :finalize_update_email, :isp_scoring, :add_play, :crash_dump, :validate_data, :google_auth, :user_event]
|
||||
before_filter :auth_user, :only => [:session_settings_show, :session_history_index, :session_user_history_index, :update, :delete, :authorizations, :test_drive_status,
|
||||
|
|
@ -178,6 +177,7 @@ ApiUsersController < ApiController
|
|||
@user.is_a_student = params[:student] if params.has_key?(:student)
|
||||
@user.is_a_teacher = params[:teacher] if params.has_key?(:teacher)
|
||||
@user.school_interest = !!params[:school_interest]
|
||||
@user.desired_package = LessonPackageType.find_by_package_type!(params[:desired_package]) if params.has_key?(:desired_package)
|
||||
@user.save
|
||||
|
||||
if @user.errors.any?
|
||||
|
|
|
|||
|
|
@ -9,16 +9,21 @@ end
|
|||
|
||||
if @test_drive
|
||||
node :test_drive do |lesson|
|
||||
attributes :teacher_id
|
||||
{teacher_id: @test_drive.id}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if @normal
|
||||
node :normal do |lesson|
|
||||
attributes :teacher_id
|
||||
{teacher_id: @normal.teacher_id}
|
||||
end
|
||||
end
|
||||
|
||||
if @lesson_package_type
|
||||
node :lesson_package_type do |lesson_package_type|
|
||||
{package_type: @lesson_package_type.package_type}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ end
|
|||
# give back more info if the user being fetched is yourself
|
||||
|
||||
if current_user && @user == current_user
|
||||
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :show_whats_next_count, :subscribe_email, :auth_twitter, :new_notifications, :sales_count, :reuse_card, :purchased_jamtracks_count, :first_downloaded_client_at, :created_at, :first_opened_jamtrack_web_player, :gifted_jamtracks, :has_redeemable_jamtrack, :remaining, :has_stored_credit_card?, :remaining_test_drives, :can_buy_test_drive?
|
||||
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :show_whats_next_count, :subscribe_email, :auth_twitter, :new_notifications, :sales_count, :reuse_card, :purchased_jamtracks_count, :first_downloaded_client_at, :created_at, :first_opened_jamtrack_web_player, :gifted_jamtracks, :has_redeemable_jamtrack, :remaining, :has_stored_credit_card?, :remaining_test_drives, :can_buy_test_drive?, :lesson_package_type_id
|
||||
|
||||
node :owned_school_id do |user|
|
||||
user.owned_school.id if user.owned_school
|
||||
|
|
|
|||
|
|
@ -403,6 +403,7 @@ script type="text/template" id="template-help-teacher-profile"
|
|||
|
||||
script type="text/template" id="template-help-side-remaining-test-drives"
|
||||
.side-remaining-test-drives
|
||||
h2 Book TestDrive Lesson
|
||||
p You currently have {{data.remaining_test_drives}} TestDrive lesson credits available.
|
||||
a.book-now.button-orange BOOK NOW!
|
||||
|
||||
|
|
@ -418,7 +419,7 @@ script type="text/template" id="template-help-side-buy-test-drive"
|
|||
script type="text/template" id="template-help-side-buy-normal-lesson"
|
||||
.side-buy-normal-lesson
|
||||
h2 Book Lesson
|
||||
p Lessons with {{data.first_name}} start at just ${{data.cheapest_lesson_stmt}}.
|
||||
p Lessons with {{data.first_name}} start at just {{data.cheapest_lesson_stmt}}.
|
||||
a.book-now.button-orange BOOK NOW!
|
||||
p Or call us at
|
||||
p 877-376-8742 (877-37-MUSIC)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
<%= render "clients/jamclass/lesson_payment" %>
|
||||
<%= render "clients/jamclass/lesson_session" %>
|
||||
<%= render "clients/jamclass/lesson_booking" %>
|
||||
<%= render "clients/jamclass/test_drive_selection" %>
|
||||
<%= render "clients/jamclass/jamclass_student" %>
|
||||
<%= render "users/feed_music_session_ajax" %>
|
||||
<%= render "users/feed_recording_ajax" %>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#lesson-booking.screen.secondary layout="screen" layout-id="jamclass/lesson-booking" layout-arg="id"
|
||||
.content-head
|
||||
.content-icon
|
||||
= image_tag "content/icon_account.png", :size => "27x20"
|
||||
= image_tag "content/icon_musicians.png", :size => "20x20"
|
||||
h1
|
||||
| jamclass
|
||||
= render "screen_navigation"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
#test-drive-selection.screen.secondary layout="screen" layout-id="jamclass/test-drive-selection" layout-arg="id"
|
||||
.content-head
|
||||
.content-icon
|
||||
= image_tag "content/icon_musicians.png", :size => "20x20"
|
||||
h1
|
||||
| jamclass
|
||||
= render "screen_navigation"
|
||||
.content-body
|
||||
= react_component 'TestDriveSelection', {}
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ namespace :lessons do
|
|||
lesson = booking.lesson_sessions[0]
|
||||
|
||||
if user.most_recent_test_drive_purchase.nil?
|
||||
LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive)
|
||||
LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive_4)
|
||||
end
|
||||
|
||||
#lesson.accept({message: 'Yeah I got this', slot: slots[0]})
|
||||
|
|
|
|||
|
|
@ -950,7 +950,7 @@ FactoryGirl.define do
|
|||
price 30.00
|
||||
|
||||
factory :test_drive_purchase do
|
||||
lesson_package_type { JamRuby::LessonPackageType.test_drive }
|
||||
lesson_package_type { JamRuby::LessonPackageType.test_drive_4 }
|
||||
association :lesson_booking, factory: :lesson_booking
|
||||
price 49.99
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ describe "Book Monthly Recurring Lesson", :js => true, :type => :feature, :capyb
|
|||
let(:user) { FactoryGirl.create(:user, traditional_band: true,paid_sessions: true, paid_sessions_hourly_rate: 1, paid_sessions_daily_rate:1 ) }
|
||||
let(:teacher_user) {FactoryGirl.create(:teacher_user, first_name: "Teacher1", ready_for_session_at: Time.now)}
|
||||
let(:teacher_user2) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)}
|
||||
let(:teacher_user3) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)}
|
||||
|
||||
after(:each) do
|
||||
Timecop.return
|
||||
|
|
@ -23,7 +24,12 @@ describe "Book Monthly Recurring Lesson", :js => true, :type => :feature, :capyb
|
|||
|
||||
UserMailer.deliveries.clear
|
||||
emulate_client
|
||||
sign_in_poltergeist user
|
||||
# create an old test drive and fakely use up all the credits so that we can book the lesson
|
||||
Timecop.travel(Date.new(2016, 03, 01))
|
||||
testdrive_lesson(user, teacher_user3)
|
||||
user.remaining_test_drives = 0
|
||||
user.save!
|
||||
user.reload
|
||||
|
||||
|
||||
teacher_user.teacher.ready_for_session_at = Time.now
|
||||
|
|
@ -38,10 +44,11 @@ describe "Book Monthly Recurring Lesson", :js => true, :type => :feature, :capyb
|
|||
|
||||
it "succeeds" do
|
||||
|
||||
visit "/client#/teachers/search"
|
||||
Timecop.travel(Date.new(2016, 04, 01))
|
||||
|
||||
# let's do a time half-way into the month, so we can prove some pro-rating
|
||||
Timecop.travel(Date.new(2016, 04, 15))
|
||||
sign_in_poltergeist user
|
||||
|
||||
visit "/client#/teachers/search"
|
||||
|
||||
find('.teacher-search-result[data-teacher-id="' + teacher_user.id + '"] .try-normal').trigger(:click)
|
||||
|
||||
|
|
@ -61,32 +68,35 @@ describe "Book Monthly Recurring Lesson", :js => true, :type => :feature, :capyb
|
|||
|
||||
find('a.book-lesson-btn', text: 'BOOK LESSON').trigger(:click)
|
||||
|
||||
find('h2', text: 'enter payment info for lesson')
|
||||
#find('h2', text: 'enter payment info for lesson')
|
||||
|
||||
user.student_lesson_bookings.count.should eql 1
|
||||
lesson_booking = user.student_lesson_bookings.first
|
||||
lesson_booking.is_requested?.should be_true
|
||||
lesson_booking.card_presumed_ok.should be_false
|
||||
lesson_booking.recurring.should be true
|
||||
lesson_booking.is_monthly_payment?.should be true
|
||||
|
||||
fill_in 'card-number', with: '4111111111111111'
|
||||
fill_in 'expiration', with: '11/2016'
|
||||
fill_in 'cvv', with: '111'
|
||||
fill_in 'zip', with: '78759'
|
||||
#fill_in 'card-number', with: '4111111111111111'
|
||||
#fill_in 'expiration', with: '11/2016'
|
||||
#fill_in 'cvv', with: '111'
|
||||
#fill_in 'zip', with: '78759'
|
||||
|
||||
find('.purchase-btn').trigger(:click)
|
||||
#find('.purchase-btn').trigger(:click)
|
||||
|
||||
# we tell user they have test drive purchased, and take them to the teacher screen
|
||||
find('#banner h1', text: 'Lesson Requested')
|
||||
# dismiss banner
|
||||
find('a.button-orange', text:'CLOSE').trigger(:click)
|
||||
|
||||
user.student_lesson_bookings.count.should eql 2
|
||||
lesson_booking = user.student_lesson_bookings.order(:created_at).last
|
||||
lesson_booking.is_requested?.should be_true
|
||||
lesson_booking.card_presumed_ok.should be_true
|
||||
lesson_booking.recurring.should be true
|
||||
lesson_booking.is_monthly_payment?.should be true
|
||||
|
||||
|
||||
lesson_booking = LessonBooking.where(teacher_id: teacher_user).first
|
||||
lesson_booking.should_not be_nil
|
||||
lesson_session = LessonSession.where(teacher_id: teacher_user).first
|
||||
lesson_session.teacher.should eql teacher_user
|
||||
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id).first
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id, teacher_id: teacher_user.id).first
|
||||
lesson_package_purchase.should be_nil
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 0
|
||||
|
|
@ -150,7 +160,7 @@ describe "Book Monthly Recurring Lesson", :js => true, :type => :feature, :capyb
|
|||
lesson_booking.recurring.should be false
|
||||
LessonSession.where(teacher_id: teacher_user2).count.should eql 1
|
||||
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id).first
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id, teacher_id: teacher_user.id).first
|
||||
lesson_package_purchase.should be_nil
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 0
|
||||
|
|
@ -176,13 +186,13 @@ describe "Book Monthly Recurring Lesson", :js => true, :type => :feature, :capyb
|
|||
lesson_session1.billed.should eql false
|
||||
lesson_session1.success.should be_true
|
||||
|
||||
user.lesson_purchases.count.should eql 0
|
||||
user.lesson_purchases.count.should eql 1
|
||||
|
||||
LessonBooking.hourly_check
|
||||
|
||||
user.reload
|
||||
lesson_package_purchase = user.lesson_purchases.count.should eql 1
|
||||
lesson_package_purchase = user.lesson_purchases.first
|
||||
lesson_package_purchase = user.lesson_purchases.count.should eql 2
|
||||
lesson_package_purchase = user.lesson_purchases.where(teacher_id: teacher_user.id).last
|
||||
teacher_distribution = lesson_package_purchase.teacher_distribution
|
||||
teacher_distribution.amount_in_cents.should eql 3000 / 2
|
||||
teacher_distribution.ready.should be_true
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
let(:user) { FactoryGirl.create(:user, traditional_band: true,paid_sessions: true, paid_sessions_hourly_rate: 1, paid_sessions_daily_rate:1 ) }
|
||||
let(:teacher_user) {FactoryGirl.create(:teacher_user, first_name: "Teacher1", ready_for_session_at: Time.now)}
|
||||
let(:teacher_user2) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)}
|
||||
let(:teacher_user3) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)}
|
||||
|
||||
after(:each) do
|
||||
Timecop.return
|
||||
|
|
@ -23,8 +24,17 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
|
||||
UserMailer.deliveries.clear
|
||||
emulate_client
|
||||
sign_in_poltergeist user
|
||||
# create an old test drive and fakely use up all the credits so that we can book the lesson
|
||||
Timecop.travel(Date.new(2016, 03, 01))
|
||||
testdrive_lesson(user, teacher_user3)
|
||||
user.remaining_test_drives = 0
|
||||
user.save!
|
||||
user.reload
|
||||
|
||||
teacher_user.teacher.ready_for_session_at = Time.now
|
||||
teacher_user.teacher.save!
|
||||
teacher_user.teacher.price_per_lesson_60_cents.should eql 3000
|
||||
Teacher.index(user, {})[:query].count.should eql 1
|
||||
|
||||
teacher_user.teacher.ready_for_session_at = Time.now
|
||||
teacher_user.teacher.save!
|
||||
|
|
@ -38,10 +48,13 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
|
||||
it "succeeds" do
|
||||
|
||||
visit "/client#/teachers/search"
|
||||
|
||||
Timecop.travel(Date.new(2016, 04, 01))
|
||||
|
||||
sign_in_poltergeist user
|
||||
|
||||
visit "/client#/teachers/search"
|
||||
|
||||
find('.teacher-search-result[data-teacher-id="' + teacher_user.id + '"] .try-normal').trigger(:click)
|
||||
|
||||
|
||||
|
|
@ -60,32 +73,35 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
|
||||
find('a.book-lesson-btn', text: 'BOOK LESSON').trigger(:click)
|
||||
|
||||
find('h2', text: 'enter payment info for lesson')
|
||||
# find('h2', text: 'enter payment info for lesson')
|
||||
|
||||
user.student_lesson_bookings.count.should eql 1
|
||||
lesson_booking = user.student_lesson_bookings.first
|
||||
lesson_booking.is_requested?.should be_true
|
||||
lesson_booking.card_presumed_ok.should be_false
|
||||
lesson_booking.recurring.should be true
|
||||
lesson_booking.is_monthly_payment?.should be false
|
||||
|
||||
fill_in 'card-number', with: '4111111111111111'
|
||||
fill_in 'expiration', with: '11/2016'
|
||||
fill_in 'cvv', with: '111'
|
||||
fill_in 'zip', with: '78759'
|
||||
#fill_in 'card-number', with: '4111111111111111'
|
||||
#fill_in 'expiration', with: '11/2016'
|
||||
#fill_in 'cvv', with: '111'
|
||||
#fill_in 'zip', with: '78759'
|
||||
|
||||
find('.purchase-btn').trigger(:click)
|
||||
#find('.purchase-btn').trigger(:click)
|
||||
|
||||
# we tell user they have test drive purchased, and take them to the teacher screen
|
||||
find('#banner h1', text: 'Lesson Requested')
|
||||
# dismiss banner
|
||||
find('a.button-orange', text:'CLOSE').trigger(:click)
|
||||
|
||||
|
||||
user.student_lesson_bookings.count.should eql 2
|
||||
lesson_booking = user.student_lesson_bookings.order(:created_at).last
|
||||
lesson_booking.is_requested?.should be_true
|
||||
lesson_booking.card_presumed_ok.should be_true
|
||||
lesson_booking.recurring.should be true
|
||||
lesson_booking.is_monthly_payment?.should be false
|
||||
|
||||
lesson_booking = LessonBooking.where(teacher_id: teacher_user).first
|
||||
lesson_booking.should_not be_nil
|
||||
lesson_session = LessonSession.where(teacher_id: teacher_user).first
|
||||
lesson_session.teacher.should eql teacher_user
|
||||
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id).first
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id, teacher_id: teacher_user.id).first
|
||||
lesson_package_purchase.should be_nil
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 0
|
||||
|
|
@ -149,7 +165,7 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
lesson_booking.recurring.should be false
|
||||
LessonSession.where(teacher_id: teacher_user2).count.should eql 1
|
||||
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id).first
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id, teacher_id: teacher_user.id).first
|
||||
lesson_package_purchase.should be_nil
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 0
|
||||
|
|
@ -175,7 +191,7 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
lesson_session1.billed.should eql true
|
||||
lesson_session1.success.should be_true
|
||||
lesson_session1.lesson_payment_charge.billed.should be_true
|
||||
lesson_session1.lesson_payment_charge.amount_in_cents.should eql 3000
|
||||
lesson_session1.lesson_payment_charge.amount_in_cents.should eql (3000 + (3000 * 0.0825).round)
|
||||
lesson_session1.lesson_payment_charge.fee_in_cents.should eql 0
|
||||
lesson_session1.lesson_payment_charge.stripe_charge_id.should_not be_nil
|
||||
lesson_session1.lesson_payment_charge.post_processed.should be_true
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ describe "Single Lesson", :js => true, :type => :feature, :capybara_feature => t
|
|||
let(:user) { FactoryGirl.create(:user, traditional_band: true,paid_sessions: true, paid_sessions_hourly_rate: 1, paid_sessions_daily_rate:1 ) }
|
||||
let(:teacher_user) {FactoryGirl.create(:teacher_user, first_name: "Teacher1", ready_for_session_at: Time.now)}
|
||||
let(:teacher_user2) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)}
|
||||
let(:teacher_user3) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)}
|
||||
|
||||
|
||||
before(:each) do
|
||||
|
|
@ -17,14 +18,16 @@ describe "Single Lesson", :js => true, :type => :feature, :capybara_feature => t
|
|||
|
||||
UserMailer.deliveries.clear
|
||||
emulate_client
|
||||
# create an old test drive and fakely use up all the credits so that we can book the lesson
|
||||
Timecop.travel(Date.new(2016, 03, 01))
|
||||
testdrive_lesson(user, teacher_user3)
|
||||
user.remaining_test_drives = 0
|
||||
user.save!
|
||||
user.reload
|
||||
sign_in_poltergeist user
|
||||
|
||||
|
||||
teacher_user.teacher.ready_for_session_at = Time.now
|
||||
teacher_user.teacher.save!
|
||||
|
||||
teacher_user.teacher.price_per_lesson_60_cents.should eql 3000
|
||||
|
||||
Teacher.index(user, {})[:query].count.should eql 1
|
||||
|
||||
|
||||
|
|
@ -62,33 +65,35 @@ describe "Single Lesson", :js => true, :type => :feature, :capybara_feature => t
|
|||
|
||||
#find('h2', text: 'your lesson has been requested')
|
||||
|
||||
find('h2', text: 'enter payment info for lesson')
|
||||
|
||||
user.student_lesson_bookings.count.should eql 1
|
||||
lesson_booking = user.student_lesson_bookings.first
|
||||
lesson_booking.is_requested?.should be_true
|
||||
lesson_booking.card_presumed_ok.should be_false
|
||||
lesson_booking.recurring.should be false
|
||||
#find('h2', text: 'enter payment info for lesson')
|
||||
|
||||
|
||||
#fill_in 'card-number', with: '4111111111111111'
|
||||
#fill_in 'expiration', with: '11/2016'
|
||||
#fill_in 'cvv', with: '111'
|
||||
#fill_in 'zip', with: '78759'
|
||||
|
||||
fill_in 'card-number', with: '4111111111111111'
|
||||
fill_in 'expiration', with: '11/2016'
|
||||
fill_in 'cvv', with: '111'
|
||||
fill_in 'zip', with: '78759'
|
||||
|
||||
find('.purchase-btn').trigger(:click)
|
||||
#find('.purchase-btn').trigger(:click)
|
||||
|
||||
# we tell user they have test drive purchased, and take them to the teacher screen
|
||||
find('#banner h1', text: 'Lesson Requested')
|
||||
# dismiss banner
|
||||
find('a.button-orange', text:'CLOSE').trigger(:click)
|
||||
lesson_booking = LessonBooking.where(teacher_id: teacher_user).first
|
||||
|
||||
user.student_lesson_bookings.count.should eql 2 # this single one, and the test drive created in the before section of the test
|
||||
lesson_booking = user.student_lesson_bookings.order(:created_at).last
|
||||
lesson_booking.is_requested?.should be_true
|
||||
lesson_booking.card_presumed_ok.should be_true
|
||||
lesson_booking.recurring.should be false
|
||||
|
||||
|
||||
|
||||
lesson_booking = LessonBooking.where(teacher_id: teacher_user).order(:created_at).last
|
||||
lesson_booking.should_not be_nil
|
||||
lesson_session = LessonSession.where(teacher_id: teacher_user).first
|
||||
lesson_session = LessonSession.where(teacher_id: teacher_user).order(:created_at).last
|
||||
lesson_session.teacher.should eql teacher_user
|
||||
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id).first
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id, teacher_id: teacher_user.id).order(:created_at).first
|
||||
lesson_package_purchase.should be_nil
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 0
|
||||
|
|
@ -151,7 +156,7 @@ describe "Single Lesson", :js => true, :type => :feature, :capybara_feature => t
|
|||
lesson_session.teacher.should eql teacher_user2
|
||||
lesson_session2 = lesson_session
|
||||
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id).first
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id, teacher_id: teacher_user.id).order(:created_at).first
|
||||
lesson_package_purchase.should be_nil
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 0
|
||||
|
|
@ -167,9 +172,9 @@ describe "Single Lesson", :js => true, :type => :feature, :capybara_feature => t
|
|||
lesson_session1.analysed.should be_true
|
||||
analysis = JSON.parse(lesson_session1.analysis)
|
||||
analysis["reason"].should eql LessonSessionAnalyser::SUCCESS
|
||||
lesson_session1.billing_attempts.should be_true
|
||||
lesson_session1.billed.should eql true
|
||||
lesson_session1.success.should be_true
|
||||
lesson_session1.billing_attempts.should eql 1
|
||||
lesson_session1.billed.should eql true
|
||||
|
||||
LessonBooking.hourly_check
|
||||
|
||||
|
|
|
|||
|
|
@ -37,18 +37,20 @@ describe "Test Drive", :js => true, :type => :feature, :capybara_feature => true
|
|||
|
||||
find('.teacher-search-result[data-teacher-id="' + teacher_user.id + '"] .try-test-drive').trigger(:click)
|
||||
|
||||
# no longer true
|
||||
# TryTestDriveDialog shows
|
||||
find('.purchase-testdrive-now').trigger(:click)
|
||||
#find('.purchase-testdrive-now').trigger(:click)
|
||||
|
||||
fill_in 'card-number', with: '4111111111111111'
|
||||
fill_in 'expiration', with: '11/2016'
|
||||
fill_in 'cvv', with: '111'
|
||||
fill_in 'zip', with: '78759'
|
||||
select_test_drive(4)
|
||||
|
||||
find('.purchase-btn').trigger(:click)
|
||||
fill_out_single_lesson
|
||||
|
||||
fill_out_payment
|
||||
|
||||
# we tell user they have test drive purchased, and take them to the teacher screen
|
||||
find('#banner h1', text: 'Test Drive Purchased')
|
||||
find('#banner .dialog-inner', text: "You have purchased #{4} TestDrive credits and have used 1 credit it to request a JamClass with #{teacher_user.name}")
|
||||
|
||||
# dismiss banner
|
||||
find('a.button-orange', text:'CLOSE').trigger(:click)
|
||||
|
||||
|
|
@ -58,35 +60,12 @@ describe "Test Drive", :js => true, :type => :feature, :capybara_feature => true
|
|||
lesson_package_purchase.lesson_package_type.is_test_drive?.should be_true
|
||||
lesson_package_purchase.lesson_payment_charge.should_not be_nil
|
||||
user.reload
|
||||
user.remaining_test_drives.should eql 4
|
||||
user.remaining_test_drives.should eql 3
|
||||
#lesson_package_purchase.amount_charged.should eql 49.99
|
||||
user.sales.count.should eql 1
|
||||
sale = user.sales.first
|
||||
sale.recurly_total_in_cents.should eql 5411
|
||||
|
||||
# the spec says take them back to search; there is some wasted effort here by the student; they have to click the teacher 2x. Ok?
|
||||
find('.teacher-search-result[data-teacher-id="' + teacher_user.id + '"] .try-test-drive').trigger(:click)
|
||||
|
||||
find('h2', text: 'book testdrive lesson')
|
||||
find('.booking-info', text: '4 TestDrive lesson credits')
|
||||
|
||||
# book the lesson
|
||||
fill_in "slot-1-date", with: "Sun Apr 17 2016"
|
||||
#find('.slot.slot-1 input.hasDatepicker').trigger(:click)
|
||||
# click 4-6
|
||||
find('td a', text: '17').trigger(:click)
|
||||
|
||||
#find('.slot.slot-2 input.hasDatepicker').trigger(:click)
|
||||
# click 4-7
|
||||
fill_in "slot-2-date", with: "Mon Apr 18 2016"
|
||||
find('td a', text: '18').trigger(:click)
|
||||
|
||||
fill_in 'user-description', with: 'abc def dog neck'
|
||||
|
||||
sleep 3
|
||||
|
||||
|
||||
find('a.book-lesson-btn', text: 'BOOK TESTDRIVE LESSON').trigger(:click)
|
||||
|
||||
find('h2', text: 'my lessons')
|
||||
|
||||
|
|
@ -112,8 +91,6 @@ describe "Test Drive", :js => true, :type => :feature, :capybara_feature => true
|
|||
find('h2', text: 'book testdrive lesson')
|
||||
find('.booking-info', text: '3 TestDrive lesson credits')
|
||||
|
||||
# dismiss banner
|
||||
find('a.button-orange', text:'CLOSE').trigger(:click)
|
||||
|
||||
# approve by teacher:
|
||||
teacher_approve(lesson_session1)
|
||||
|
|
|
|||
|
|
@ -28,4 +28,90 @@ def teacher_approve(lesson_session)
|
|||
find('.schedule.button-orange').trigger(:click)
|
||||
visit "/client#/jamclass"
|
||||
find('tr[data-lesson-session-id="' + lesson_session.id + '"] .displayStatusColumn', text: 'Scheduled')
|
||||
end
|
||||
end
|
||||
|
||||
def fill_out_single_lesson
|
||||
|
||||
find('h2', text: 'book testdrive lesson')
|
||||
find('.booking-info', text: 'If you need to cancel')
|
||||
|
||||
# book the lesson
|
||||
fill_in "slot-1-date", with: "Sun Apr 17 2016"
|
||||
#find('.slot.slot-1 input.hasDatepicker').trigger(:click)
|
||||
# click 4-6
|
||||
find('td a', text: '17').trigger(:click)
|
||||
|
||||
#find('.slot.slot-2 input.hasDatepicker').trigger(:click)
|
||||
# click 4-7
|
||||
fill_in "slot-2-date", with: "Mon Apr 18 2016"
|
||||
find('td a', text: '18').trigger(:click)
|
||||
|
||||
fill_in 'user-description', with: 'abc def dog neck'
|
||||
|
||||
sleep 3
|
||||
|
||||
|
||||
find('a.book-lesson-btn', text: 'BOOK TESTDRIVE LESSON').trigger(:click)
|
||||
|
||||
end
|
||||
|
||||
def fill_out_payment
|
||||
|
||||
fill_in 'card-number', with: '4111111111111111'
|
||||
fill_in 'expiration', with: '11/2016'
|
||||
fill_in 'cvv', with: '111'
|
||||
fill_in 'zip', with: '78759'
|
||||
|
||||
find('.purchase-btn').trigger(:click)
|
||||
end
|
||||
|
||||
def select_test_drive(count = 4)
|
||||
find(".button-orange.select-#{count}").trigger(:click)
|
||||
end
|
||||
|
||||
def create_stripe_token(exp_month = 2017)
|
||||
Stripe::Token.create(
|
||||
:card => {
|
||||
:number => "4111111111111111",
|
||||
:exp_month => 2,
|
||||
:exp_year => exp_month,
|
||||
:cvc => "314"
|
||||
},
|
||||
).id
|
||||
end
|
||||
|
||||
|
||||
def testdrive_lesson(user, teacher, slots = nil)
|
||||
|
||||
if slots.nil?
|
||||
slots = []
|
||||
slots << FactoryGirl.build(:lesson_booking_slot_single)
|
||||
slots << FactoryGirl.build(:lesson_booking_slot_single)
|
||||
end
|
||||
|
||||
if !user.stored_credit_card
|
||||
token = create_stripe_token
|
||||
user.payment_update({token: token, zip: '78759'})
|
||||
user.save!
|
||||
user.stored_credit_card.should be_true
|
||||
end
|
||||
|
||||
|
||||
booking = LessonBooking.book_test_drive(user, teacher, slots, "Hey I've heard of you before.")
|
||||
#puts "BOOKING #{booking.errors.inspect}"
|
||||
booking.errors.any?.should be_false
|
||||
lesson = booking.lesson_sessions[0]
|
||||
booking.card_presumed_ok.should be_true
|
||||
|
||||
if user.most_recent_test_drive_purchase.nil?
|
||||
LessonPackagePurchase.create(user, booking, LessonPackageType.test_drive_4)
|
||||
end
|
||||
|
||||
lesson.accept({message: 'Yeah I got this', slot: slots[0]})
|
||||
lesson.errors.any?.should be_false
|
||||
lesson.reload
|
||||
lesson.slot.should eql slots[0]
|
||||
lesson.status.should eql LessonSession::STATUS_APPROVED
|
||||
|
||||
lesson
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue