VRFS-4037 - create a interested in school landing page
This commit is contained in:
parent
2835941834
commit
fea26d82f5
|
|
@ -342,4 +342,5 @@ jamblaster_connection.sql
|
|||
teacher_progression.sql
|
||||
teacher_complete.sql
|
||||
lessons.sql
|
||||
lessons_unread_messages.sql
|
||||
lessons_unread_messages.sql
|
||||
track_school_signups.sql
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE USERS ADD COLUMN school_interest BOOLEAN DEFAULT FALSE;
|
||||
|
|
@ -36,6 +36,14 @@ module JamRuby
|
|||
subject: options[:subject])
|
||||
end
|
||||
|
||||
def partner(options)
|
||||
mail(to: APP_CONFIG.email_partners_alias,
|
||||
from: APP_CONFIG.email_generic_from,
|
||||
body: options[:body],
|
||||
content_type: "text/plain",
|
||||
subject: options[:subject])
|
||||
end
|
||||
|
||||
def recurly_alerts(user, options)
|
||||
|
||||
body = options[:body]
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def self.analyse_sessions
|
||||
MusicSession.joins(lesson_session: :lesson_booking).where("session_removed_at IS NOT NULL OR NOW() > scheduled_start + (INTERVAL '1 minutes' * duration)").where('analysed = false').each do |music_session|
|
||||
MusicSession.joins(lesson_session: :lesson_booking).where('lesson_sessions.status = ?', LessonSession::STATUS_APPROVED).where("session_removed_at IS NOT NULL OR NOW() > scheduled_start + (INTERVAL '1 minutes' * duration)").where('analysed = false').each do |music_session|
|
||||
lession_session = music_session.lesson_session
|
||||
lession_session.analyse
|
||||
end
|
||||
|
|
@ -122,13 +122,13 @@ module JamRuby
|
|||
|
||||
def self.complete_sessions
|
||||
# this will find any paid session (recurring monthly paid, recurring single paid, single paid)
|
||||
MusicSession.joins(lesson_session: [:lesson_booking, :lesson_payment_charge]).where("session_removed_at IS NOT NULL OR NOW() > scheduled_start + (INTERVAL '1 minutes' * duration)").where('analysed = true').where('lesson_sessions.post_processed = false').where('billing_should_retry = true').each do |music_session|
|
||||
MusicSession.joins(lesson_session: [:lesson_booking, :lesson_payment_charge]).where('lesson_sessions.status = ?', LessonSession::STATUS_COMPLETED).where("session_removed_at IS NOT NULL OR NOW() > scheduled_start + (INTERVAL '1 minutes' * duration)").where('analysed = true').where('lesson_sessions.post_processed = false').where('billing_should_retry = true').each do |music_session|
|
||||
lession_session = music_session.lesson_session
|
||||
lession_session.session_completed
|
||||
end
|
||||
|
||||
# test drives don't have a lesson_payment_charge, so we don't join against them
|
||||
MusicSession.joins(lesson_session: [:lesson_booking]).where('lesson_sessions.lesson_type = ?', LESSON_TYPE_TEST_DRIVE).where("session_removed_at IS NOT NULL OR NOW() > scheduled_start + (INTERVAL '1 minutes' * duration)").where('analysed = true').where('lesson_sessions.post_processed = false').each do |music_session|
|
||||
MusicSession.joins(lesson_session: [:lesson_booking]).where('lesson_sessions.status = ?', LessonSession::STATUS_COMPLETED).where('lesson_sessions.lesson_type = ?', LESSON_TYPE_TEST_DRIVE).where("session_removed_at IS NOT NULL OR NOW() > scheduled_start + (INTERVAL '1 minutes' * duration)").where('analysed = true').where('lesson_sessions.post_processed = false').each do |music_session|
|
||||
lession_session = music_session.lesson_session
|
||||
lession_session.session_completed
|
||||
end
|
||||
|
|
@ -142,7 +142,7 @@ module JamRuby
|
|||
half_hour_from_now = Time.zone.local_to_utc(half_hour_from_now)
|
||||
end
|
||||
|
||||
MusicSession.joins(lesson_session: [:lesson_booking]).where('sent_starting_notice = false').where('(scheduled_start > ? and scheduled_start < ?)', now, half_hour_from_now).each do |music_session|
|
||||
MusicSession.joins(lesson_session: [:lesson_booking]).where('lesson_sessions.status = ?', LessonSession::STATUS_APPROVED).where('sent_starting_notice = false').where('(scheduled_start > ? and scheduled_start < ?)', now, half_hour_from_now).each do |music_session|
|
||||
lession_session = music_session.lesson_session
|
||||
lession_session.send_starting_notice
|
||||
end
|
||||
|
|
@ -162,7 +162,7 @@ module JamRuby
|
|||
|
||||
self.status = STATUS_COMPLETED
|
||||
|
||||
if lesson_booking.requires_teacher_distribution?(self)
|
||||
if success && lesson_booking.requires_teacher_distribution?(self)
|
||||
self.teacher_distribution = TeacherDistribution.create_for_lesson(self)
|
||||
end
|
||||
|
||||
|
|
@ -304,7 +304,7 @@ module JamRuby
|
|||
else
|
||||
if !sent_notices
|
||||
# bad session; just poke user
|
||||
UserMailer.student_weekly_recurring_no_bill(student, self).deliver
|
||||
UserMailer.student_lesson_normal_no_bill(self).deliver
|
||||
self.sent_notices = true
|
||||
self.sent_notices_at = Time.now
|
||||
self.post_processed = true
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ module JamRuby
|
|||
STUDENT_NOT_THERE_WHEN_JOINED = 'student_not_there_when_joined'
|
||||
JOINED_LATE = 'did_not_join_on_time'
|
||||
NO_SHOW = 'no_show'
|
||||
NEITHER_SHOW = 'neither_show'
|
||||
|
||||
|
||||
# what are the potential results?
|
||||
|
|
@ -62,14 +63,13 @@ module JamRuby
|
|||
teacher_ranges = merge_overlapping_ranges(all_teacher_ranges)
|
||||
|
||||
intersecting = intersecting_ranges(student_ranges, teacher_ranges)
|
||||
|
||||
student_analysis = analyse_intersection(lesson_session, student_ranges)
|
||||
teacher_analysis = analyse_intersection(lesson_session, teacher_ranges)
|
||||
together_analysis = analyse_intersection(lesson_session, intersecting)
|
||||
|
||||
# spec: https://jamkazam.atlassian.net/wiki/display/PS/Product+Specification+-+JamClass#ProductSpecification-JamClass-TeacherReceives&RespondstoLessonBookingRequest
|
||||
|
||||
if music_session.session_removed_at.nil? || (music_session.scheduled_start + (lesson_session.duration * 60)) < Time.now
|
||||
if music_session.session_removed_at.nil? && !((music_session.scheduled_start + (lesson_session.duration * 60)) < Time.now)
|
||||
reason = SESSION_ONGOING
|
||||
bill = false
|
||||
else
|
||||
|
|
@ -107,6 +107,8 @@ module JamRuby
|
|||
reason = STUDENT_FAULT
|
||||
elsif teacher
|
||||
reason = TEACHER_FAULT
|
||||
else
|
||||
reason = NEITHER_SHOW
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -150,7 +152,8 @@ module JamRuby
|
|||
|
||||
|
||||
def self.analyse_intersection(lesson_session, ranges)
|
||||
start = lesson_session.scheduled_start
|
||||
# be sure to call .to_time on any ActiveRecord time, because we get a ton of deprecation warninsg about Time#succ if you use ActiveSupport:: TimeZone
|
||||
start = lesson_session.scheduled_start.to_time
|
||||
planned_duration_seconds = lesson_session.duration * 60
|
||||
end_time = start + planned_duration_seconds
|
||||
|
||||
|
|
@ -286,7 +289,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def self.ranges_overlap?(a, b)
|
||||
a.include?(b.begin) || b.include?(a.begin)
|
||||
a.cover?(b.begin) || b.cover?(a.begin)
|
||||
end
|
||||
|
||||
def self.merge_ranges(a, b)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ module JamRuby
|
|||
end
|
||||
|
||||
def range
|
||||
Range.new(created_at, session_removed_at || Time.now)
|
||||
# to_time to not use ActiveSupport::TimeWithZone
|
||||
session_removed_at_time = session_removed_at.to_time if session_removed_at
|
||||
Range.new(created_at.to_time, session_removed_at_time || Time.now.to_time)
|
||||
end
|
||||
|
||||
def music_session
|
||||
|
|
|
|||
|
|
@ -1090,6 +1090,7 @@ module JamRuby
|
|||
teacher = options[:teacher]
|
||||
school_invitation_code = options[:school_invitation_code]
|
||||
school_id = options[:school_id]
|
||||
school_interest = options[:school_interest]
|
||||
|
||||
user = User.new
|
||||
user.validate_instruments = true
|
||||
|
|
@ -1115,6 +1116,7 @@ module JamRuby
|
|||
user.has_redeemable_jamtrack = true
|
||||
user.is_a_student = !!student
|
||||
user.is_a_teacher = !!teacher
|
||||
user.school_interest = !!school_interest
|
||||
if user.is_a_student || user.is_a_teacher
|
||||
musician = true
|
||||
end
|
||||
|
|
@ -1331,6 +1333,10 @@ module JamRuby
|
|||
UserMailer.welcome_message(user).deliver
|
||||
end
|
||||
|
||||
if user.school_interest
|
||||
AdminMailer.partner({body: "#{user.email} signed up via the /landing/jamclass/schools page.", subject: "#{user.email} is interested in schools"})
|
||||
end
|
||||
|
||||
if !user.email_confirmed
|
||||
# any errors here should also rollback the transaction; that's OK. If emails aren't going to be delivered,
|
||||
# it's already a really bad situation; make user signup again
|
||||
|
|
|
|||
|
|
@ -13,6 +13,32 @@ describe LessonSessionAnalyser do
|
|||
let(:valid_recurring_slots) { [lesson_booking_slot_recurring1, lesson_booking_slot_recurring2] }
|
||||
|
||||
describe "analyse" do
|
||||
|
||||
after{
|
||||
Timecop.return
|
||||
}
|
||||
it "neither show" do
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
music_session = lesson.music_session
|
||||
|
||||
Timecop.freeze((lesson.music_session.scheduled_start + lesson.duration * 60) + 1)
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
analysis[:reason].should eql LessonSessionAnalyser::NEITHER_SHOW
|
||||
analysis[:student].should eql nil
|
||||
analysis[:bill].should be false
|
||||
|
||||
student = analysis[:student_analysis]
|
||||
student[:joined_on_time].should be false
|
||||
student[:joined_late].should be false
|
||||
student[:waited_correctly].should be false
|
||||
student[:initial_waiting_pct].should eql nil
|
||||
student[:potential_waiting_time].should eql nil
|
||||
|
||||
together = analysis[:together_analysis]
|
||||
together[:session_time].should eql 0
|
||||
end
|
||||
|
||||
it "teacher joined on time, waited, student no show" do
|
||||
lesson = testdrive_lesson(user, teacher)
|
||||
music_session = lesson.music_session
|
||||
|
|
@ -57,7 +83,6 @@ describe LessonSessionAnalyser do
|
|||
|
||||
|
||||
analysis = LessonSessionAnalyser.analyse(lesson)
|
||||
puts analysis
|
||||
analysis[:reason].should eql LessonSessionAnalyser::STUDENT_FAULT
|
||||
analysis[:student].should eql LessonSessionAnalyser::JOINED_LATE
|
||||
analysis[:bill].should be true
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ def app_config
|
|||
'http://localhost:3333'
|
||||
end
|
||||
|
||||
def email_partners_alias
|
||||
'partners@jamkazam.com'
|
||||
end
|
||||
|
||||
def email_social_alias
|
||||
'social@jamkazam.com'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -286,19 +286,22 @@ UserStore = context.UserStore
|
|||
links = []
|
||||
|
||||
matches = {}
|
||||
for problem, isPresent of user.teacher.profile_pct_summary
|
||||
data = @lookup[problem]
|
||||
if data? && !isPresent
|
||||
matches[data.name] = data
|
||||
if user.teacher?
|
||||
for problem, isPresent of user.teacher.profile_pct_summary
|
||||
data = @lookup[problem]
|
||||
if data? && !isPresent
|
||||
matches[data.name] = data
|
||||
|
||||
for name, data of matches
|
||||
if !data.text?
|
||||
links.push(`<a key={data.name} className="missing-profile" onClick={this.missingProfileClick.bind(this, data)}>{data.name}</a>`)
|
||||
for name, data of matches
|
||||
if !data.text?
|
||||
links.push(`<a key={data.name} className="missing-profile" onClick={this.missingProfileClick.bind(this, data)}>{data.name}</a>`)
|
||||
|
||||
for name, data of matches
|
||||
if data.text?
|
||||
links.push(`<a key={data.name} onClick={this.onProfileHelp.bind(this, data)} className="missing-profile">{data.name}</a>`)
|
||||
`<ul className="missing-profile-list">{links}</ul>`
|
||||
for name, data of matches
|
||||
if data.text?
|
||||
links.push(`<a key={data.name} onClick={this.onProfileHelp.bind(this, data)} className="missing-profile">{data.name}</a>`)
|
||||
`<ul className="missing-profile-list">{links}</ul>`
|
||||
else
|
||||
null
|
||||
|
||||
onProfileHelp: (data, e) ->
|
||||
e.preventDefault()
|
||||
|
|
@ -388,6 +391,9 @@ UserStore = context.UserStore
|
|||
teacherProfileUri = "/client#/profile/teacher/#{this.state.user.id}"
|
||||
pct = Math.round(this.state.user.teacher?.profile_pct)
|
||||
|
||||
if !pct?
|
||||
pct = 0
|
||||
|
||||
if pct == 100
|
||||
pctCompleteMsg = `<p className="pct-complete">Your teacher profile is {pct}% complete.</p>`
|
||||
else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,433 @@
|
|||
context = window
|
||||
rest = context.JK.Rest()
|
||||
|
||||
@JamClassSchoolLandingBottomPage = React.createClass({
|
||||
|
||||
render: () ->
|
||||
`<div className="top-container">
|
||||
<div className="row awesome jam-class teachers">
|
||||
<h2 className="awesome">How JamClass by JamKazam Can Help Your Music School</h2>
|
||||
|
||||
<p>Online music lessons offer obvious advantages to your school. You can reach students who live
|
||||
|
||||
more than 30 minutes away – even students across the country. Teach during normal “off
|
||||
|
||||
hours”, when students in your area are tied up at school or at work. And students and parents
|
||||
|
||||
are increasingly interested in online lessons to avoid the time and hassle of traveling to/from
|
||||
|
||||
your school.</p>
|
||||
|
||||
<p>Several companies have built online marketplaces of music teachers, but these markets haven’t
|
||||
|
||||
offered a partnering model for existing schools. And even if they had, online music lessons
|
||||
|
||||
haven’t taken off like other online Internet markets. Why? Because every one of these markets
|
||||
|
||||
has relied on Skype or similar apps – built for voice chat – to deliver online music lessons. This is
|
||||
|
||||
a major problem. Voice technology makes music sound awful in online sessions – so bad that
|
||||
|
||||
teachers can’t assess the student’s tone and sometimes even the pitch of what they are
|
||||
|
||||
playing. These apps also have very high latency – a technical term that means that the student
|
||||
|
||||
and teacher cannot play together, another critical requirement for productive lessons. Since
|
||||
|
||||
Skype wasn’t built for music, it also lacks many other basic features to support effective lessons,
|
||||
|
||||
like a metronome, mixers, backing tracks, etc.</p>
|
||||
|
||||
<p>At JamKazam, we’ve spent years designing, patenting, and building technology specifically to
|
||||
|
||||
enable musicians to play online live in sync with studio quality audio. We’ve built a wide variety
|
||||
|
||||
of critical online music performance features into this platform. And now we’ve built a lesson
|
||||
|
||||
marketplace on top of this foundation to match students to teachers, and we’re investing in
|
||||
|
||||
marketing to drive students into the market.</p>
|
||||
|
||||
<p>
|
||||
The bottom line is that your school can now effectively offer and teach online lessons to
|
||||
|
||||
students using our incredible technology. If you secure students through your own marketing
|
||||
|
||||
initiatives, it’s free to use JamKazam. And if we bring new students to your school, we keep a
|
||||
|
||||
portion of the lesson income for these students, helping you to grow your business, increasing
|
||||
|
||||
your revenues and profitability.</p>
|
||||
<p>If this sounds interesting to you, read on to learn more about some of the top features of
|
||||
|
||||
JamClass by JamKazam.</p>
|
||||
|
||||
<div className="testimonials jam-class teachers">
|
||||
<h3>JamClass Kudos</h3>
|
||||
|
||||
<div className="testimonial">
|
||||
<img src="/assets/landing/Julie Bonk - Jam Class - Speech Bubble.png" className="testimonial-speech-bubble"/>
|
||||
<img src="/assets/landing/Julie Bonk - Avatar.png" className="testimonial-avatar"/>
|
||||
<h4><strong>Julie Bonk</strong></h4>
|
||||
<div className="testiminal-background">
|
||||
Oft-recorded pianist, teacher, mentor to Grammy winner Norah Jones and Scott Hoying of Pentatonix
|
||||
</div>
|
||||
</div>
|
||||
<div className="testimonial">
|
||||
<img src="/assets/landing/Carl Brown - Jam Class - Speech Bubble.png" className="testimonial-speech-bubble"/>
|
||||
<img src="/assets/landing/Carl Brown - Avatar.png" className="testimonial-avatar"/>
|
||||
<a rel="external" href="https://www.youtube.com/channel/UCvnfBBzEizi1T5unOXNCxdQ"><img
|
||||
src="/assets/landing/Carl Brown - YouTube.png" className="testimonial-youtube"/></a>
|
||||
<h4><strong>Carl Brown</strong> of GuitarLessions365</h4>
|
||||
</div>
|
||||
<div className="testimonial">
|
||||
<img src="/assets/landing/Justin Pierce - Jam Class - Speech Bubble.png" className="testimonial-speech-bubble"/>
|
||||
<img src="/assets/landing/Justin Pierce - Avatar.png" className="testimonial-avatar"/>
|
||||
<h4><strong>Justin Pierce</strong></h4>
|
||||
<div className="testiminal-background">
|
||||
Masters degree in jazz studies, performer in multiple bands, saxophone instructor
|
||||
</div>
|
||||
</div>
|
||||
<div className="testimonial">
|
||||
<img src="/assets/landing/Dave Sebree - Jam Class - Speech Bubble.png" className="testimonial-speech-bubble"/>
|
||||
<img src="/assets/landing/Dave Sebree - Avatar.png" className="testimonial-avatar"/>
|
||||
<h4><strong>Dave Sebree</strong></h4>
|
||||
<div className="testiminal-background">
|
||||
Founder of Austin School of Music, Gibson-endorsed guitarist, touring musician
|
||||
</div>
|
||||
</div>
|
||||
<div className="testimonial">
|
||||
<img src="/assets/landing/Sara Nelson - Jam Class - Speech Bubble.png" className="testimonial-speech-bubble"/>
|
||||
<img src="/assets/landing/Sara Nelson - Avatar.png" className="testimonial-avatar"/>
|
||||
<h4><strong>Sara Nelson</strong></h4>
|
||||
<div className="testiminal-background">
|
||||
Cellist for Austin Lyric Opera, frequently recorded with major artists
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome-thing jam-class">
|
||||
<div className="awesome-item">
|
||||
<h3>
|
||||
<div className="awesome-number">1</div>
|
||||
Play Live In Sync From Different Locations
|
||||
</h3>
|
||||
<p>
|
||||
<div className="video-wrapper right">
|
||||
<div className="video-container">
|
||||
<iframe src="//www.youtube.com/embed/I2reeNKtRjg" frameborder="0" allowfullscreen="allowfullscreen"/>
|
||||
</div>
|
||||
</div>
|
||||
<p>Teacher and student need to be able to play together to enable effective lessons. As any teacher who has
|
||||
attempted to teach using Skype will tell you, Skype doesn't let you play together. JamKazam's patented
|
||||
technologies deliver on this requirement at an amazing level. Click the video above to watch 6 bands play
|
||||
together from different locations to see our tech in action. And for an even more impressive feat, <a
|
||||
href="https://www.youtube.com/watch?v=2Zk7-04IAx4" target="_blank">watch this video</a> with a band
|
||||
playing together from Austin, Atlanta, Chicago, and Brooklyn using JamKazam tech.</p>
|
||||
|
||||
<div className="clearall"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome-thing jam-class">
|
||||
<div className="awesome-item">
|
||||
<h3>
|
||||
<div className="awesome-number">2</div>
|
||||
Studio Quality Audio
|
||||
</h3>
|
||||
<p>
|
||||
<div className="audio-wrapper">
|
||||
<a href="https://www.jamkazam.com/recordings/94c5d5aa-2c61-440a-93a4-c661bf77d4a8" target="_blank">Sample
|
||||
Session Audio #1</a>
|
||||
|
||||
<div className="sample-audio-text">Electric Guitars & Drum</div>
|
||||
<a href="https://www.jamkazam.com/recordings/4916dbfe-0eeb-4bfb-b08a-4085dfecedcb" target="_blank">Sample
|
||||
Session Audio #2</a>
|
||||
|
||||
<div className="sample-audio-text">Acoustic Guitar, Bass & Voice</div>
|
||||
<a href="https://www.jamkazam.com/recordings/5875be7e-2cc3-4555-825c-046bd2f849e7" target="_blank">Sample
|
||||
Session Audio #3</a>
|
||||
|
||||
<div className="sample-audio-text">Trumpet & Keys</div>
|
||||
|
||||
<p className="listening-note">These audio links will open a new tab in your browser. When done listening,
|
||||
close the tab and return to this page.</p>
|
||||
</div>
|
||||
<p>Skype was built for voice - for people talking with each other. It uses something called a "voice codec".
|
||||
This just means it processes all audio as a spoken human voice, and the result is that music, whether
|
||||
instrumental or vocal, sounds very bad in Skype, as it has been processed through tech built for talking.
|
||||
JamKazam delivers very high quality audio. You will be amazed at how good it sounds. It sounds like you're
|
||||
sitting next to each other playing. This is also critical for a good lesson. Poor audio is hard to endure
|
||||
in lessons.</p>
|
||||
|
||||
<div className="clearall"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome-thing jam-class">
|
||||
<div className="awesome-item">
|
||||
<h3>
|
||||
<div className="awesome-number">3</div>
|
||||
Get Student Referrals from the Marketplace
|
||||
</h3>
|
||||
<p>
|
||||
<img className="teacher-marketplace awesome-image right" src="/assets/landing/marketplace.png" width="221" height="223"/>
|
||||
<p>You can use JamKazam's superior applications and services to conduct better online music
|
||||
|
||||
lessons with your existing students, and to attract new students through your own marketing
|
||||
|
||||
efforts. In addition, even schools are challenged to invest the resources to attract new students.
|
||||
|
||||
Our JamClass marketplace adds value to your business in this area as well, as JamKazam invests
|
||||
|
||||
every month to drive new students into our marketplace, and delivers these qualified students
|
||||
|
||||
to you, set up and ready to go for online lessons. This is explained in more detail later on this
|
||||
|
||||
page.</p>
|
||||
|
||||
<div className="clearall"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome-thing jam-class">
|
||||
<div className="awesome-item">
|
||||
<h3>
|
||||
<div className="awesome-number">4</div>
|
||||
Record Lessons & Student Performances
|
||||
</h3>
|
||||
<p>
|
||||
<div className="video-wrapper left">
|
||||
<div className="video-container">
|
||||
<iframe src="//www.youtube.com/embed/OcnIxqmfkfU" frameborder="0" allowfullscreen="allowfullscreen"/>
|
||||
</div>
|
||||
<div className="cta-text">watch this sample video recording from a lesson</div>
|
||||
</div>
|
||||
<p>Many times a student thinks they've got it during a lesson, but they get home and realize "I don't got it", and then they've wasted a week. In JamClass the instructor can record all or portions of a lesson that the student can easily refer back to later. You can also have students record their performances, and you can review them together.</p>
|
||||
|
||||
<div className="clearall"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome-thing jam-class">
|
||||
<div className="awesome-item">
|
||||
<h3>
|
||||
<div className="awesome-number">5</div>
|
||||
Use JamTracks to Motivate Students
|
||||
</h3>
|
||||
<p>
|
||||
<div className="video-wrapper right">
|
||||
<div className="video-container">
|
||||
<iframe src="//www.youtube.com/embed/07zJC7C2ICA" frameborder="0" allowfullscreen="allowfullscreen"/>
|
||||
</div>
|
||||
</div>
|
||||
<p>Teachers usually apply the techniques taught in lessons to playing songs - ideally songs your student loves. JamKazam makes this better too, as we offer a catalog of 3,700+ songs. Each song is is a complete multi-track recording, with fully isolated tracks for each part of the music - e.g. lead vocal, backing vocals, lead guitar, rhythm guitar, keys, bass, drums, etc. So your student can listen to just the part they're learning in isolation, turn around and mute that one part to play along with the rest of the band, slow down playback for practice, record and share your performances, and more. It's really fun! And a great way to keep your students movitated and engaged.</p>
|
||||
|
||||
<div className="clearall"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome-thing jam-class">
|
||||
<div className="awesome-item">
|
||||
<h3>
|
||||
<div className="awesome-number">6</div>
|
||||
Broadcast Recitals
|
||||
</h3>
|
||||
<p>
|
||||
<img src="/assets/landing/YouTube Logo.png" className="awesome-image right" width="264" height="117"/>
|
||||
|
||||
<p>Recitals are an important tool for teachers, but recitals are lost using Skype. With JamClass, you can live broadcast video and audio of student recitals through YouTube. This enables other students, family members, and friends to "tune in" for recital performances. And when students share the link to their recitals with their friends, it can also serve as great exposure for your lessons, attracting friends of your existing students as new students.</p>
|
||||
|
||||
<div className="clearall"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome-thing jam-class">
|
||||
<div className="awesome-item">
|
||||
<h3>
|
||||
<div className="awesome-number">7</div>
|
||||
Apply VST & AU Audio Plug-In Effects
|
||||
</h3>
|
||||
<p>
|
||||
<img src="/assets/landing/Top 10 Image - Number 6.png" className="awesome-image left" width="350"
|
||||
height="240"/>
|
||||
|
||||
<p>The free JamKazam app lets you easily apply VST & AU plugin effects to your live performance in lessons.
|
||||
For example, guitarists can apply popular amp sims like AmpliTube to get any kind of guitar tone without
|
||||
pedal boards or amps, and vocalists can apply effects like reverb, pitch correction, etc.</p>
|
||||
|
||||
<div className="clearall"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome-thing jam-class">
|
||||
<div className="awesome-item">
|
||||
<h3>
|
||||
<div className="awesome-number">8</div>
|
||||
Use MIDI Instruments
|
||||
</h3>
|
||||
<p>
|
||||
<img src="/assets/landing/Top 10 Image - Number 7.png" className="awesome-image" width="320" height="257"/>
|
||||
|
||||
<p>The free JamKazam app also lets you use MIDI instruments in online lesson sessions. For example, keys
|
||||
players can use MIDI keyboard controllers with VST & AU plugins to generate traditional piano sounds,
|
||||
Rhodes electric piano, Hammond organ, and other classic keys tones. And drummers who use electronic kits
|
||||
can use their favorite plugins to power their percussive audio.</p>
|
||||
|
||||
<div className="clearall"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome-thing jam-class multi-para">
|
||||
<div className="awesome-item">
|
||||
<h3>
|
||||
<div className="awesome-number">9</div>
|
||||
And So Much More...
|
||||
</h3>
|
||||
<p>
|
||||
<p>There are many other features that are specifically useful for online lessons built into JamClass by JamKazam, including a metronome feature, the ability for either teacher or student to open any audio file and use it as a backing track for session acccompaniment, and too many more to list.</p>
|
||||
|
||||
<p>In addition to the lesson features, an awesome bonus is that once your students are set up to
|
||||
|
||||
play with your teachers in online lessons, they can also play completely FREE with anyone else
|
||||
|
||||
in the JamKazam community any time to use the skills they’re learning in lessons to play with
|
||||
|
||||
others, which again reinforces and motivates students to stay engaged, as it’s more fun to play
|
||||
|
||||
with others than alone. If you teach ensembles and rock bands, your students can practice in
|
||||
|
||||
groups between lessons without having to find rehearsal space, pack gear, and travel. Plus
|
||||
|
||||
there are thousands of online sessions played every month on the JamKazam service, including
|
||||
|
||||
open jam sessions set up by our user community, and students can hop into these sessions,
|
||||
|
||||
create their own improptu sessions, etc. It's a vibrant and welcoming community of fellow
|
||||
|
||||
musicians.</p>
|
||||
|
||||
<div className="clearall"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row awesome jam-class">
|
||||
<h2 className="awesome">What Does Your School Need to Host JamClass Lessons?</h2>
|
||||
|
||||
<p>
|
||||
At a mininum, you need:</p>
|
||||
<ul>
|
||||
<li>A computer running either
|
||||
<ul>
|
||||
<li>Windows 7 or a later version (32-bit or 64-bit)
|
||||
</li>
|
||||
<li>Mac OS X 10.7 or a later version (64-bit)<br/>
|
||||
<a className="how-do-i" href="https://support.apple.com/en-us/HT201948" target="_blank">how do I know
|
||||
which version I'm running and if it's 64-bit on Mac?</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>A built-in microphone and built-in webcam on your computer</li>
|
||||
<li>Internet service with at least 1Mbps upload bandwidth<br/>
|
||||
<a className="how-do-i" href="http://www.speedtest.net/" target="_blank">how do I know how much upload
|
||||
bandwidth my Internet service delivers?</a></li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
To have very high quality audio in your sessions, rather than using the built-in microphone on your computer
|
||||
to capture your instrumental and/or vocal audio, we strongly recommend using an external audio interface. An
|
||||
audio interface is a hardware product that connects to your computer and processes audio better than your
|
||||
computer alone. If you already own/use an audio interface, you can use the one you have. And if you don't,
|
||||
please <a href="https://jamkazam.desk.com/customer/portal/articles/1292412-choosing-an-audio-device"
|
||||
target="_blank">read this help article on audio interfaces</a> that can guide you to get what you
|
||||
need. You can pick up a perfectly good interface very inexpensively, typically for less than $50. And you can
|
||||
use your new interface not just for JamClass, but also to make home recordings of your performances, etc. So
|
||||
it's a great thing to have for any musician.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you feel worried or confused about getting set up because you're not a "tech genius", we are happy to work
|
||||
with you 1:1 to answer your questions, and walk you through picking gear and setting it up.
|
||||
We'll even hop into an online test session with you and your school’s teachers, show you
|
||||
around the key features, and make sure all your teachers are ready to rock and roll online!
|
||||
</p>
|
||||
</div>
|
||||
<div className="row awesome jam-class">
|
||||
<h2 className="awesome">How Do the Business Aspects of JamClass Work?</h2>
|
||||
|
||||
<p>You can use JamClass by JamKazam to teach your own existing students if they'd like to take
|
||||
|
||||
online lessons, and it’s free to use in this way for schools, much like Skype.</p>
|
||||
|
||||
<p>If you would like JamKazam to bring new students to your school through the JamClass
|
||||
|
||||
marketplace, we will be making substantial marketing investments in attracting, equipping, and
|
||||
|
||||
delivering these students to you. JamKazam will bill and collect payments directly from these
|
||||
|
||||
referred students. You and your teachers set your prices for lessons just as you do today. We
|
||||
|
||||
retain a minority percentage of the lesson revenue from these referred students, and we will
|
||||
|
||||
transfer the majority balance of these lesson revenues to your school. The school is then
|
||||
|
||||
responsible to distribute lesson payments to its teachers according to the school’s agreements
|
||||
|
||||
with its teachers, whatever those may be. Also, as the school operator, you may choose to have
|
||||
|
||||
all lesson booking requests from the JamClass marketplace come directly to you as the school
|
||||
|
||||
administrator, so that you handle scheduling and booking for all these online lessons, just as
|
||||
|
||||
you already do for lessons on premise at your school. Once you have set the date/time for
|
||||
|
||||
these lessons, they will then appear on each teacher’s JamClass dashboard. So when using
|
||||
|
||||
JamClass you, as the school owner, may continue to manage scheduling and distribution of
|
||||
|
||||
earnings to your school’s teachers.</p>
|
||||
|
||||
<p>Finally, please note that to participate in the JamClass marketplace, each teacher will need to
|
||||
|
||||
opt in to participate in our TestDrive program. TestDrive is a core component of our JamClass
|
||||
|
||||
marketing programs, providing students interested in taking online lessons with discounted
|
||||
|
||||
introductory packages to get started. To participate in the marketplace, each teacher must be
|
||||
|
||||
willing to teach at least 2 TestDrive lessons per week. Your school is paid $10 for each 30-
|
||||
|
||||
minute TestDrive lesson, and many TestDrive students will become long-term students who pay
|
||||
|
||||
your normal rates. Teachers may opt to accept more than 2 TestDrive lessons per week if they
|
||||
|
||||
would like to grow their student base more rapidly.</p>
|
||||
</div>
|
||||
|
||||
<div id="what-now" className="row awesome jam-class">
|
||||
<h2 className="awesome">What Now?</h2>
|
||||
|
||||
<p>
|
||||
If you're ready to sign up your school, or you think this might be good for your school but are
|
||||
|
||||
not sure yet, scroll back up to the top of this page, and enter your email address and a
|
||||
|
||||
password to sign up. Once you've done this, we'll reach out to you to answer any and all
|
||||
|
||||
questions you have. If you find you want to move forward, we’ll work with you directly to help
|
||||
|
||||
you get your school ready to go.
|
||||
</p>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
context = window
|
||||
rest = context.JK.Rest()
|
||||
|
||||
@JamClassSchoolLandingPage = React.createClass({
|
||||
|
||||
render: () ->
|
||||
|
||||
|
||||
loggedIn = context.JK.currentUserId?
|
||||
|
||||
if this.state.done
|
||||
ctaButtonText = 'sending you in...'
|
||||
else if this.state.processing
|
||||
ctaButtonText = 'hold on...'
|
||||
else
|
||||
if loggedIn
|
||||
ctaButtonText = "SIGN UP"
|
||||
else
|
||||
ctaButtonText = "SIGN UP"
|
||||
|
||||
if loggedIn
|
||||
register = `<button className={classNames({'cta-button' : true, 'processing': this.state.processing})} onClick={this.ctaClick}>{ctaButtonText}</button>`
|
||||
else
|
||||
|
||||
if this.state.loginErrors?
|
||||
for key, value of this.state.loginErrors
|
||||
break
|
||||
|
||||
errorText = context.JK.getFullFirstError(key, this.state.loginErrors, {email: 'Email', password: 'Password', 'terms_of_service' : 'The terms of service'})
|
||||
|
||||
register = `<div className="register-area jam-class">
|
||||
<div className={classNames({'errors': true, 'active': this.state.loginErrors})}>
|
||||
{errorText}
|
||||
</div>
|
||||
<form className="jamtrack-signup-form">
|
||||
<label>Email: </label><input type="text" name="email" />
|
||||
<label>Password: </label><input type="password" name="password" />
|
||||
<div className="clearall"/>
|
||||
<input className="terms-checkbox" type="checkbox" name="terms" /><label className="terms-help">I have read and agree to the JamKazam <a href="/corp/terms" onClick={this.termsClicked}>terms of service</a></label>
|
||||
<div className="clearall"/>
|
||||
<button className={classNames({'cta-button' : true, 'processing': this.state.processing})} onClick={this.ctaClick}>{ctaButtonText}</button>
|
||||
</form>
|
||||
</div>`
|
||||
|
||||
|
||||
`<div className="top-container">
|
||||
<div className="full-row name-and-artist">
|
||||
<div>
|
||||
<img className="jam-class-teacher" width="375" height="215" src="/assets/landing/jam_class.png" alt="teacher instructing a jam class"/>
|
||||
<h1 className="jam-track-name">GROW YOUR SCHOOL’S MARKET REACH & INCOME</h1>
|
||||
<h2 className="original-artist">Do you own/operate a music school?</h2>
|
||||
<div className="clearall"/>
|
||||
</div>
|
||||
<div className="preview-and-action-box jamclass">
|
||||
<img src="/assets/landing/arrow-1-student.png" className="arrow1-jamclass" />
|
||||
<div className="preview-jamtrack-header">
|
||||
Sign Up Your School
|
||||
</div>
|
||||
<div className={classNames({'preview-area': true, 'jam-class': true})}>
|
||||
<p>Sign up to let us know you’re interested in partnering, and we’ll follow up to answer your
|
||||
|
||||
questions.</p>
|
||||
<p>If this is a good fit for your school, we’ll give you all the 1:1 help you need to get your school
|
||||
|
||||
and staff up and running.</p>
|
||||
<p>We will not share your email. See our <a href="/corp/privacy" onClick={this.privacyPolicy}>privacy policy</a></p>
|
||||
{register}
|
||||
<p>Learn how we can help you greatly extend your reach to new markets while increasing your
|
||||
|
||||
revenues.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row summary-text">
|
||||
<p className="top-summary">
|
||||
Founded by a team that has built and sold companies to Google, eBay, GameStop and more,
|
||||
|
||||
JamKazam has developed incredibly unique technology that lets musicians play together live in
|
||||
|
||||
sync with studio quality audio from different locations over the Internet. Now JamKazam has
|
||||
|
||||
launched an online music lesson marketplace, and we’ve set up a program specifically to
|
||||
|
||||
partner with music schools to help you attract and engage students across the country,
|
||||
|
||||
extending your school’s reach and generating more income.
|
||||
</p>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
getInitialState: () ->
|
||||
{loginErrors: null, processing:false}
|
||||
|
||||
privacyPolicy: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
context.JK.popExternalLink('/corp/privacy')
|
||||
|
||||
termsClicked: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
context.JK.popExternalLink('/corp/terms')
|
||||
|
||||
componentDidMount:() ->
|
||||
$root = $(this.getDOMNode())
|
||||
$checkbox = $root.find('.terms-checkbox')
|
||||
context.JK.checkbox($checkbox)
|
||||
|
||||
# add item to cart, create the user if necessary, and then place the order to get the free JamTrack.
|
||||
ctaClick: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
return if @state.processing
|
||||
|
||||
@setState({loginErrors: null})
|
||||
|
||||
loggedIn = context.JK.currentUserId?
|
||||
|
||||
if loggedIn
|
||||
@markTeacher()
|
||||
else
|
||||
@createUser()
|
||||
|
||||
@setState({processing:true})
|
||||
|
||||
|
||||
markTeacher: () ->
|
||||
rest.updateUser({school_interest: true})
|
||||
.done((response) =>
|
||||
this.setState({done: true})
|
||||
context.location = '/client#/home'
|
||||
)
|
||||
.fail((jqXHR) =>
|
||||
this.setState({processing: false})
|
||||
context.JK.app.notifyServerError(jqXHR, "Unable to Mark As Interested in School")
|
||||
)
|
||||
|
||||
createUser: () ->
|
||||
$form = $('.jamtrack-signup-form')
|
||||
email = $form.find('input[name="email"]').val()
|
||||
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, school_interest: true})
|
||||
.done((response) =>
|
||||
context.location = '/client#/home'
|
||||
).fail((jqXHR) =>
|
||||
@setState({processing:false})
|
||||
if jqXHR.status == 422
|
||||
response = JSON.parse(jqXHR.responseText)
|
||||
if response.errors
|
||||
@setState({loginErrors: response.errors})
|
||||
else
|
||||
context.JK.app.notify({title: 'Unknown Signup Error', text: jqXHR.responseText})
|
||||
else
|
||||
context.JK.app.notifyServerError(jqXHR, "Unable to Sign Up")
|
||||
)
|
||||
|
||||
|
||||
@setState({processing:true})
|
||||
})
|
||||
|
|
@ -101,7 +101,23 @@ rest = context.JK.Rest()
|
|||
|
||||
loggedIn = context.JK.currentUserId?
|
||||
|
||||
if loggedIn
|
||||
@markStudent()
|
||||
else
|
||||
@createUser()
|
||||
|
||||
@setState({processing:true})
|
||||
|
||||
markStudent: () ->
|
||||
rest.updateUser({student: true})
|
||||
.done((response) =>
|
||||
this.setState({done: true})
|
||||
context.location = '/client#/profile/' + context.JK.currentUserId
|
||||
)
|
||||
.fail((jqXHR) =>
|
||||
this.setState({processing: false})
|
||||
context.JK.app.notifyServerError(jqXHR, "Unable to Mark As Student")
|
||||
)
|
||||
|
||||
createUser: () ->
|
||||
$form = $('.jamtrack-signup-form')
|
||||
|
|
@ -109,10 +125,10 @@ 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})
|
||||
rest.signup({email: email, password: password, first_name: null, last_name: null, terms:terms, student : true})
|
||||
.done((response) =>
|
||||
|
||||
|
||||
@setState({done: true})
|
||||
context.location = '/client#/profile/' + response.id
|
||||
).fail((jqXHR) =>
|
||||
@setState({processing:false})
|
||||
if jqXHR.status == 422
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ ApiUsersController < ApiController
|
|||
teacher: params[:teacher],
|
||||
school_invitation_code: params[:school_invitation_code],
|
||||
school_id: params[:school_id],
|
||||
school_interest: params[:school_interest],
|
||||
affiliate_referral_id: cookies[:affiliate_visitor]
|
||||
}
|
||||
|
||||
|
|
@ -176,6 +177,7 @@ ApiUsersController < ApiController
|
|||
@user.update_calendars(params[:calendars]) if params.has_key?(:calendars)
|
||||
@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.save
|
||||
|
||||
if @user.errors.any?
|
||||
|
|
|
|||
|
|
@ -109,6 +109,14 @@ class LandingsController < ApplicationController
|
|||
end
|
||||
|
||||
|
||||
def jam_class_schools
|
||||
enable_olark
|
||||
@no_landing_tag = true
|
||||
@landing_tag_play_learn_earn = true
|
||||
@show_after_black_bar_border = true
|
||||
render 'jam_class_schools', layout: 'web'
|
||||
end
|
||||
|
||||
def individual_jamtrack
|
||||
|
||||
enable_olark
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
- provide(:page_name, 'landing_page full individual_jamtrack')
|
||||
- provide(:description, @description)
|
||||
- provide(:title, @title)
|
||||
|
||||
= react_component 'JamClassSchoolLandingPage', @page_data.to_json
|
||||
|
||||
- content_for :after_black_bar do
|
||||
.row.cta-row
|
||||
h2 SIGN UP YOUR SCHOOL NOW!
|
||||
p To reach and effectively teach students more than 30 minutes away.
|
||||
p.cta-text Not sure if our school partner program is for you? Scroll down to learn more.
|
||||
|
||||
- content_for :white_bar do
|
||||
= react_component 'JamClassSchoolLandingBottomPage', @page_data.to_json
|
||||
|
|
@ -242,6 +242,7 @@ if defined?(Bundler)
|
|||
config.estimated_slow_mixdown_time = 80
|
||||
config.num_packaging_nodes = 2
|
||||
|
||||
config.email_partners_alias = 'partners@jamkazam.com'
|
||||
config.email_social_alias = 'social@jamkazam.com'
|
||||
config.email_crashes_alias = 'clientcrash@jamkazam.com'
|
||||
config.email_alerts_alias = 'alerts@jamkazam.com' # should be used for 'oh no' server down/service down sorts of emails
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ SampleApp::Application.configure do
|
|||
config.email_alerts_alias = ENV['ALERT_EMAIL'] || 'alerts-dev@jamkazam.com'
|
||||
config.email_crashes_alias = ENV['ALERT_EMAIL'] || 'clientcrash-dev@jamkazam.com'
|
||||
config.email_social_alias = ENV['ALERT_EMAIL'] || 'social-dev@jamkazam.com'
|
||||
config.email_partners_alias = ENV['ALERT_EMAIL'] || 'partners-dev@jamkazam.com'
|
||||
config.guard_against_fraud = true
|
||||
config.guard_against_browser_fraud = true
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ SampleApp::Application.routes.draw do
|
|||
match '/landing/jamclass/free/students', to: 'landings#jam_class_students_free', via: :get
|
||||
match '/landing/jamclass/teachers', to: 'landings#jam_class_teachers', via: :get, as: 'jamclass_teacher_signup'
|
||||
match '/landing/jamclass/affiliates', to: 'landings#jam_class_affiliates', via: :get
|
||||
match '/landing/jamclass/schools', to: 'landings#jam_class_schools', via: :get
|
||||
|
||||
match '/affiliateProgram', to: 'landings#affiliate_program', via: :get, as: 'affiliate_program'
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class UserManager < BaseManager
|
|||
teacher = options[:teacher]
|
||||
school_invitation_code = options[:school_invitation_code]
|
||||
school_id = options[:school_id]
|
||||
school_interest = options[:school_interest]
|
||||
|
||||
recaptcha_failed = false
|
||||
unless options[:skip_recaptcha] # allow callers to opt-of recaptcha
|
||||
|
|
@ -82,7 +83,8 @@ class UserManager < BaseManager
|
|||
student: student,
|
||||
teacher: teacher,
|
||||
school_invitation_code: school_invitation_code,
|
||||
school_id: school_id)
|
||||
school_id: school_id,
|
||||
school_interest: school_interest)
|
||||
user
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ FactoryGirl.define do
|
|||
|
||||
factory :teacher_user do
|
||||
after(:create) do |user, evaluator|
|
||||
user.password_confirmation = nil
|
||||
teacher = FactoryGirl.create(:teacher, user: user, price_per_lesson_60_cents: 3000, price_per_month_60_cents: 3000, lesson_duration_60: true, prices_per_lesson: true, prices_per_month: true)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,8 +8,14 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
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)}
|
||||
|
||||
after(:each) do
|
||||
Timecop.return
|
||||
end
|
||||
|
||||
|
||||
before(:each) do
|
||||
|
||||
|
||||
LessonBooking.destroy_all
|
||||
Recording.delete_all
|
||||
Diagnostic.delete_all
|
||||
|
|
@ -22,22 +28,14 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
|
||||
teacher_user.teacher.ready_for_session_at = Time.now
|
||||
teacher_user.teacher.save!
|
||||
|
||||
teacher_user.password.should eql 'foobar'
|
||||
teacher_user.teacher.price_per_lesson_60_cents.should eql 3000
|
||||
|
||||
Teacher.index(user, {})[:query].count.should eql 1
|
||||
|
||||
|
||||
end
|
||||
|
||||
def finish_lesson_successfully
|
||||
|
||||
end
|
||||
|
||||
describe "register via showing interesting in teacher 1st" do
|
||||
after(:each) do
|
||||
Timecop.return
|
||||
end
|
||||
|
||||
it "succeeds" do
|
||||
|
||||
visit "/client#/teachers/search"
|
||||
|
|
@ -145,11 +143,11 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
# dismiss banner
|
||||
find('a.button-orange', text:'CLOSE').trigger(:click)
|
||||
|
||||
|
||||
lesson_booking = LessonBooking.where(teacher_id: teacher_user2).first
|
||||
lesson_booking.should_not be_nil
|
||||
lesson_booking.recurring.should be false
|
||||
lesson_session = LessonSession.where(teacher_id: teacher_user2).first
|
||||
lesson_session.teacher.should eql teacher_user2
|
||||
LessonSession.where(teacher_id: teacher_user2).count.should eql 1
|
||||
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id).first
|
||||
lesson_package_purchase.should be_nil
|
||||
|
|
@ -157,7 +155,58 @@ describe "Book Single Recurring Lesson", :js => true, :type => :feature, :capyba
|
|||
user.remaining_test_drives.should eql 0
|
||||
user.sales.count.should eql 0
|
||||
|
||||
finish_lesson_successfully
|
||||
|
||||
# approve by teacher:
|
||||
lesson_session1 = LessonSession.where(teacher_id: teacher_user).first
|
||||
teacher_approve(lesson_session1)
|
||||
|
||||
lesson_booking1 = LessonBooking.where(teacher_id: teacher_user).first
|
||||
lesson_booking1.lesson_sessions.count.should eql 2
|
||||
lesson_session2 = LessonSession.where(teacher_id: teacher_user).last
|
||||
|
||||
successful_lesson(lesson_session1)
|
||||
|
||||
LessonSession.hourly_check
|
||||
lesson_session1.reload
|
||||
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
|
||||
|
||||
LessonBooking.hourly_check
|
||||
|
||||
lesson_session1.reload
|
||||
teacher_distribution = lesson_session1.teacher_distribution
|
||||
teacher_distribution.amount_in_cents.should eql 3000
|
||||
teacher_distribution.ready.should be_true
|
||||
teacher_distribution.distributed.should be_false
|
||||
|
||||
# check the second session, which hasn't come due yet because it's 1 week ahead of the other session
|
||||
lesson_session2.reload
|
||||
lesson_session2.analysed.should be_true
|
||||
analysis = JSON.parse(lesson_session2.analysis)
|
||||
analysis["reason"].should eql LessonSessionAnalyser::SESSION_ONGOING
|
||||
lesson_session2.billing_attempts.should eql 0
|
||||
lesson_session2.billed.should eql false
|
||||
lesson_session2.success.should be_false
|
||||
lesson_session2.teacher_distribution.should be_nil
|
||||
|
||||
failed_lesson(lesson_session2)
|
||||
|
||||
LessonSession.hourly_check
|
||||
LessonBooking.hourly_check
|
||||
|
||||
# check the 2nd session again, which should now have
|
||||
lesson_session2.reload
|
||||
lesson_session2.analysed.should be_true
|
||||
analysis = JSON.parse(lesson_session2.analysis)
|
||||
analysis["reason"].should eql LessonSessionAnalyser::SESSION_ONGOING
|
||||
lesson_session2.billing_attempts.should eql 0
|
||||
lesson_session2.billed.should eql false
|
||||
lesson_session2.success.should be_false
|
||||
lesson_session2.teacher_distribution.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -28,10 +28,6 @@ describe "Single Lesson", :js => true, :type => :feature, :capybara_feature => t
|
|||
Teacher.index(user, {})[:query].count.should eql 1
|
||||
|
||||
|
||||
end
|
||||
|
||||
def finish_lesson_successfully
|
||||
|
||||
end
|
||||
|
||||
describe "register via showing interesting in teacher 1st" do
|
||||
|
|
@ -148,10 +144,12 @@ describe "Single Lesson", :js => true, :type => :feature, :capybara_feature => t
|
|||
# dismiss banner
|
||||
find('a.button-orange', text:'CLOSE').trigger(:click)
|
||||
|
||||
lesson_session1 = lesson_session
|
||||
lesson_booking = LessonBooking.where(teacher_id: teacher_user2).first
|
||||
lesson_booking.should_not be_nil
|
||||
lesson_session = LessonSession.where(teacher_id: teacher_user2).first
|
||||
lesson_session.teacher.should eql teacher_user2
|
||||
lesson_session2 = lesson_session
|
||||
|
||||
lesson_package_purchase = LessonPackagePurchase.where(user_id: user.id).first
|
||||
lesson_package_purchase.should be_nil
|
||||
|
|
@ -159,7 +157,48 @@ describe "Single Lesson", :js => true, :type => :feature, :capybara_feature => t
|
|||
user.remaining_test_drives.should eql 0
|
||||
user.sales.count.should eql 0
|
||||
|
||||
finish_lesson_successfully
|
||||
# approve by teacher:
|
||||
teacher_approve(lesson_session1)
|
||||
|
||||
successful_lesson(lesson_session1)
|
||||
|
||||
LessonSession.hourly_check
|
||||
lesson_session1.reload
|
||||
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
|
||||
|
||||
LessonBooking.hourly_check
|
||||
|
||||
lesson_session1.reload
|
||||
teacher_distribution = lesson_session1.teacher_distribution
|
||||
teacher_distribution.amount_in_cents.should eql 3000
|
||||
teacher_distribution.ready.should be_true
|
||||
teacher_distribution.distributed.should be_false
|
||||
|
||||
# check the second session, which no one went too
|
||||
|
||||
|
||||
lesson_session2.reload
|
||||
lesson_session2.analysed.should be_false
|
||||
|
||||
# approve by teacher:
|
||||
teacher_approve(lesson_session2)
|
||||
LessonSession.hourly_check
|
||||
LessonBooking.hourly_check
|
||||
|
||||
lesson_session2.reload
|
||||
lesson_session2.analysed.should be_true
|
||||
analysis = JSON.parse(lesson_session2.analysis)
|
||||
analysis["reason"].should eql LessonSessionAnalyser::NEITHER_SHOW
|
||||
lesson_session2.billing_attempts.should eql 0
|
||||
lesson_session2.billed.should eql false
|
||||
lesson_session2.success.should be_false
|
||||
|
||||
lesson_session2.teacher_distribution.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ describe "Test Drive", :js => true, :type => :feature, :capybara_feature => true
|
|||
|
||||
end
|
||||
|
||||
def finish_lesson_successfully
|
||||
|
||||
def finish_lesson_successfully(lesson_session)
|
||||
successful_lesson(lesson_session)
|
||||
end
|
||||
|
||||
describe "register via showing interesting in teacher 1st" do
|
||||
|
|
@ -101,6 +101,8 @@ describe "Test Drive", :js => true, :type => :feature, :capybara_feature => true
|
|||
lesson_booking = user.student_lesson_bookings.first
|
||||
lesson_booking.is_requested?.should be_true
|
||||
user.remaining_test_drives.should eql 3
|
||||
lesson_booking.lesson_sessions.count.should eql 1
|
||||
lesson_session1 = lesson_booking.lesson_sessions.first
|
||||
|
||||
|
||||
# let's make sure we can ask for another test drive too!
|
||||
|
|
@ -116,8 +118,31 @@ 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)
|
||||
|
||||
successful_lesson(lesson_session1)
|
||||
|
||||
LessonSession.hourly_check
|
||||
lesson_session1.reload
|
||||
lesson_session1.analysed.should be_true
|
||||
analysis = JSON.parse(lesson_session1.analysis)
|
||||
analysis["reason"].should eql LessonSessionAnalyser::SUCCESS
|
||||
lesson_session1.billing_attempts.should be_nil
|
||||
lesson_session1.billed.should eql false
|
||||
lesson_session1.success.should be_true
|
||||
|
||||
LessonBooking.hourly_check
|
||||
|
||||
lesson_session1.reload
|
||||
teacher_distribution = lesson_session1.teacher_distribution
|
||||
teacher_distribution.amount_in_cents.should eql 1000
|
||||
teacher_distribution.ready.should be_true
|
||||
teacher_distribution.distributed.should be_false
|
||||
|
||||
finish_lesson_successfully
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "School Landing", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
subject { page }
|
||||
|
||||
before(:all) do
|
||||
ShoppingCart.delete_all
|
||||
JamTrackRight.delete_all
|
||||
JamTrack.delete_all
|
||||
JamTrackTrack.delete_all
|
||||
JamTrackLicensor.delete_all
|
||||
end
|
||||
|
||||
|
||||
let(:user) { FactoryGirl.create(:user, country: 'US') }
|
||||
|
||||
|
||||
it "logged out" do
|
||||
visit "/landing/jamclass/schools"
|
||||
|
||||
find('h1.jam-track-name', 'GROW YOUR SCHOOL’S MARKET REACH & INCOME')
|
||||
find('h2.original-artist', 'Do you own/operate a music school?')
|
||||
|
||||
find('button.cta-button', text: 'SIGN UP').trigger(:click)
|
||||
|
||||
# should fail because we haven't filled out email/password/terms
|
||||
find('.register-area .errors', text: "Email can't be blank")
|
||||
|
||||
fill_in "email", with: 'school_interest_123@jamkazam.com'
|
||||
fill_in "password", with: 'jam123'
|
||||
find('.register-area ins', visible: false).trigger(:click)
|
||||
find('button.cta-button', text: 'SIGN UP').trigger(:click)
|
||||
|
||||
# this should show on the /client#/home page (WILL CHANGE)
|
||||
find('h2', text: 'sessions')
|
||||
|
||||
user = User.find_by_email('school_interest_123@jamkazam.com')
|
||||
user.is_a_student.should be false
|
||||
user.is_a_teacher.should be false
|
||||
user.school_interest.should be true
|
||||
user.musician.should be true
|
||||
end
|
||||
|
||||
it "logged in" do
|
||||
fast_signin(user,"/landing/jamclass/schools")
|
||||
|
||||
find('h1.jam-track-name', 'GROW YOUR SCHOOL’S MARKET REACH & INCOME')
|
||||
find('h2.original-artist', 'Do you own/operate a music school?')
|
||||
|
||||
find('button.cta-button', text: 'SIGN UP').trigger(:click)
|
||||
|
||||
# this should show on the /client#/home page (WILL CHANGE)
|
||||
find('h2', text: 'sessions')
|
||||
|
||||
user.reload
|
||||
user.is_a_student.should be false
|
||||
user.is_a_teacher.should be false
|
||||
user.school_interest.should be true
|
||||
user.musician.should be true
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -33,7 +33,7 @@ describe "Student Landing", :js => true, :type => :feature, :capybara_feature =>
|
|||
find('button.cta-button', text: 'SIGN UP').trigger(:click)
|
||||
|
||||
# this should show on the /client#/home page (WILL CHANGE)
|
||||
find('h2', text: 'create session')
|
||||
find('h1', text: 'musician profile')
|
||||
|
||||
user = User.find_by_email('student_123@jamkazam.com')
|
||||
user.is_a_student.should be true
|
||||
|
|
@ -50,7 +50,7 @@ describe "Student Landing", :js => true, :type => :feature, :capybara_feature =>
|
|||
find('button.cta-button', text: 'TRY TESTDRIVE').trigger(:click)
|
||||
|
||||
# this should show on the /client#/home page (WILL CHANGE)
|
||||
find('h2', text: 'create session')
|
||||
find('h1', text: 'musician profile')
|
||||
|
||||
user.reload
|
||||
user.is_a_student.should be true
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ describe "Teacher Landing", :js => true, :type => :feature, :capybara_feature =>
|
|||
find('h1.jam-track-name', 'JAMCLASS')
|
||||
find('h2.original-artist', 'Finally, online music lessons that really work!')
|
||||
|
||||
find('button.cta-button', text: 'SIGN UP').trigger(:click)
|
||||
find('button.cta-button', text: 'Sign Up').trigger(:click)
|
||||
|
||||
# should fail because we haven't filled out email/password/terms
|
||||
find('.register-area .errors', text: "Email can't be blank")
|
||||
|
|
@ -30,15 +30,16 @@ describe "Teacher Landing", :js => true, :type => :feature, :capybara_feature =>
|
|||
fill_in "email", with: 'teacher_123@jamkazam.com'
|
||||
fill_in "password", with: 'jam123'
|
||||
find('.register-area ins', visible: false).trigger(:click)
|
||||
find('button.cta-button', text: 'SIGN UP').trigger(:click)
|
||||
find('button.cta-button', text: 'Sign Up').trigger(:click)
|
||||
|
||||
# this should show on the /client#/home page (WILL CHANGE)
|
||||
find('h2', text: 'create session')
|
||||
find('h2', text: 'edit teacher profile: introduction')
|
||||
|
||||
user = User.find_by_email('teacher_123@jamkazam.com')
|
||||
user.is_a_student.should be false
|
||||
user.is_a_teacher.should be true
|
||||
user.musician.should be true
|
||||
user.school_interest.should be false
|
||||
end
|
||||
|
||||
it "logged in" do
|
||||
|
|
@ -47,15 +48,16 @@ describe "Teacher Landing", :js => true, :type => :feature, :capybara_feature =>
|
|||
find('h1.jam-track-name', 'JAMCLASS')
|
||||
find('h2.original-artist', 'Finally, online music lessons that really work!')
|
||||
|
||||
find('button.cta-button', text: 'BECOME A TEACHER').trigger(:click)
|
||||
find('button.cta-button', text: 'Enter Teacher Profile').trigger(:click)
|
||||
|
||||
# this should show on the /client#/home page (WILL CHANGE)
|
||||
find('h2', text: 'create session')
|
||||
find('h2', text: 'edit teacher profile: introduction')
|
||||
|
||||
user.reload
|
||||
user.is_a_student.should be false
|
||||
user.is_a_teacher.should be true
|
||||
user.musician.should be true
|
||||
user.school_interest.should be false
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ describe UserManager do
|
|||
user.reload
|
||||
expect(user.affiliate_referral).to eq(partner)
|
||||
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
end
|
||||
|
||||
it "signup successfully with instruments" do
|
||||
|
|
@ -345,7 +345,7 @@ describe UserManager do
|
|||
musician: true,
|
||||
signup_confirm_url: "http://localhost:3000/confirm")
|
||||
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
user.errors.any?.should be_false
|
||||
|
||||
# exactly the same parameters; should dup on email, and send no email
|
||||
|
|
@ -359,7 +359,7 @@ describe UserManager do
|
|||
instruments: @instruments,
|
||||
musician: true,
|
||||
signup_confirm_url: "http://localhost:3000/confirm")
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
user.errors.any?.should be_true
|
||||
user.errors[:email][0].should == "has already been taken"
|
||||
end
|
||||
|
|
@ -375,7 +375,7 @@ describe UserManager do
|
|||
instruments: @instruments,
|
||||
musician: true,
|
||||
signup_confirm_url: "http://localhost:3000/confirm")
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
user.errors.any?.should be_false
|
||||
user.name.should eq 'Anonymous'
|
||||
end
|
||||
|
|
@ -545,7 +545,7 @@ describe UserManager do
|
|||
user.friends?(@some_user).should be_true
|
||||
user.friends?(@some_user).should be_true
|
||||
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
end
|
||||
|
||||
it "signup successfully with facebook signup additional info" do
|
||||
|
|
@ -603,7 +603,7 @@ describe UserManager do
|
|||
user.user_authorizations[0].token = fb_signup.token
|
||||
user.user_authorizations[0].token_expiration = fb_signup.token_expires_at
|
||||
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
end
|
||||
|
||||
it "fail to signup when facebook UID already taken" do
|
||||
|
|
@ -721,7 +721,7 @@ describe UserManager do
|
|||
location: @loca,
|
||||
student: true,
|
||||
signup_confirm_url: "http://localhost:3000/confirm")
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
user.errors.any?.should be_false
|
||||
user = User.find(user.id)
|
||||
user.has_redeemable_jamtrack.should be_true
|
||||
|
|
@ -742,7 +742,7 @@ describe UserManager do
|
|||
location: @loca,
|
||||
teacher: true,
|
||||
signup_confirm_url: "http://localhost:3000/confirm")
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
user.errors.any?.should be_false
|
||||
user = User.find(user.id)
|
||||
user.has_redeemable_jamtrack.should be_true
|
||||
|
|
@ -763,7 +763,7 @@ describe UserManager do
|
|||
location: @loca,
|
||||
teacher: true,
|
||||
signup_confirm_url: "http://localhost:3000/confirm")
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
user.errors.any?.should be_false
|
||||
user = User.find(user.id)
|
||||
user.has_redeemable_jamtrack.should be_true
|
||||
|
|
@ -782,7 +782,7 @@ describe UserManager do
|
|||
terms_of_service: true,
|
||||
location: @loca,
|
||||
signup_confirm_url: "http://localhost:3000/confirm")
|
||||
UserMailer.deliveries.length.should == 1
|
||||
UserMailer.deliveries.length.should == 2
|
||||
user.errors.any?.should be_false
|
||||
user = User.find(user.id)
|
||||
user.has_redeemable_jamtrack.should be_true
|
||||
|
|
|
|||
|
|
@ -142,6 +142,10 @@ def web_config
|
|||
:source_customer => 'cus_88Vp44SLnBWMXq' # seth@jamkazam.com in JamKazam-test account
|
||||
}
|
||||
end
|
||||
|
||||
def email_partners_alias
|
||||
"partner-dev@jamkazam.com"
|
||||
end
|
||||
end
|
||||
klass.new
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
def successful_lesson(lesson_session, advance_to_end = true)
|
||||
# teacher & student get into session
|
||||
start = lesson_session.scheduled_start
|
||||
end_time = lesson_session.scheduled_start + (60 * lesson_session.duration)
|
||||
uh2 = FactoryGirl.create(:music_session_user_history, user: lesson_session.teacher, history: lesson_session.music_session, created_at: start, session_removed_at: end_time)
|
||||
uh2 = FactoryGirl.create(:music_session_user_history, user: lesson_session.student, history: lesson_session.music_session, created_at: start, session_removed_at: end_time)
|
||||
# artificially end the session, which is covered by other background jobs
|
||||
lesson_session.music_session.session_removed_at = end_time
|
||||
lesson_session.music_session.save!
|
||||
|
||||
if advance_to_end
|
||||
Timecop.travel(end_time + 60 * 60)
|
||||
end
|
||||
end
|
||||
|
||||
def failed_lesson(lesson_session, advance_to_end = true)
|
||||
start = lesson_session.scheduled_start
|
||||
end_time = lesson_session.scheduled_start + (60 * lesson_session.duration)
|
||||
if advance_to_end
|
||||
Timecop.travel(end_time + 60 * 60)
|
||||
end
|
||||
end
|
||||
def teacher_approve(lesson_session)
|
||||
|
||||
sign_out_poltergeist(validate: true)
|
||||
sign_in_poltergeist(lesson_session.teacher, password: 'foobar')
|
||||
visit "/client#/jamclass/lesson-booking/" + lesson_session.id
|
||||
find('.schedule.button-orange').trigger(:click)
|
||||
visit "/client#/jamclass"
|
||||
find('tr[data-lesson-session-id="' + lesson_session.id + '"] .displayStatusColumn', text: 'Scheduled')
|
||||
end
|
||||
|
|
@ -141,6 +141,9 @@ def sign_in_poltergeist(user, options = {})
|
|||
validate = options[:validate]
|
||||
validate = true if validate.nil?
|
||||
|
||||
if user.password.nil? && !options[:password]
|
||||
raise "user has no password. Use a user newly created so that it's password is still present"
|
||||
end
|
||||
uri = URI.parse(current_url)
|
||||
|
||||
# in tests, we often have an issue where an old signin screen is unloading
|
||||
|
|
@ -157,7 +160,7 @@ def sign_in_poltergeist(user, options = {})
|
|||
|
||||
within('#landing-inner form.signin-form') do
|
||||
fill_in "Email Address:", with: user.email
|
||||
fill_in "Password:", with: user.password
|
||||
fill_in "Password:", with: options[:password] || user.password
|
||||
click_button "SIGN IN"
|
||||
end
|
||||
|
||||
|
|
@ -186,7 +189,7 @@ def set_login_cookie(user)
|
|||
page.driver.set_cookie(:remember_token, user.remember_token)
|
||||
end
|
||||
|
||||
def sign_out()
|
||||
def sign_out
|
||||
if Capybara.javascript_driver == :poltergeist
|
||||
page.driver.remove_cookie(:remember_token)
|
||||
else
|
||||
|
|
|
|||
Loading…
Reference in New Issue