672 lines
27 KiB
CoffeeScript
672 lines
27 KiB
CoffeeScript
context = window
|
|
rest = context.JK.Rest()
|
|
logger = context.JK.logger
|
|
|
|
UserStore = context.UserStore
|
|
|
|
@LessonPayment = React.createClass({
|
|
|
|
mixins: [
|
|
ICheckMixin,
|
|
Reflux.listenTo(AppStore, "onAppInit"),
|
|
Reflux.listenTo(UserStore, "onUserChanged")
|
|
]
|
|
|
|
shouldShowNameSet: false
|
|
|
|
onAppInit: (@app) ->
|
|
@app.bindScreen('jamclass/lesson-payment',
|
|
{beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide})
|
|
|
|
onUserChanged: (userState) ->
|
|
|
|
if !@shouldShowNameSet
|
|
@shouldShowNameSet = true
|
|
if userState?.user?
|
|
username = userState.user.name
|
|
first_name = userState.user.first_name
|
|
last_name = userState.user.last_name
|
|
shouldShowName = !username? || username.trim() == '' || username.toLowerCase().indexOf('anonymous') > -1
|
|
else
|
|
shouldShowName = @state.shouldShowName
|
|
|
|
@setState({user: userState?.user, shouldShowName: shouldShowName})
|
|
|
|
|
|
componentDidMount: () ->
|
|
@checkboxes = [{selector: 'input.billing-address-in-us', stateKey: 'billingInUS'}]
|
|
|
|
@root = $(@getDOMNode())
|
|
@root.find('input.expiration').payment('formatCardExpiry')
|
|
@root.find("input.card-number").payment('formatCardNumber')
|
|
@root.find("input.cvv").payment('formatCardCVC')
|
|
@iCheckify()
|
|
|
|
componentDidUpdate: () ->
|
|
@iCheckify()
|
|
|
|
getInitialState: () ->
|
|
{
|
|
user: null,
|
|
lesson: null,
|
|
updating: false,
|
|
billingInUS: true,
|
|
userWantsUpdateCC: false,
|
|
"test-drive": false,
|
|
teacher: null,
|
|
package: null
|
|
}
|
|
|
|
beforeHide: (e) ->
|
|
@resetErrors()
|
|
|
|
beforeShow: (e) ->
|
|
|
|
afterShow: (e) ->
|
|
@resetState()
|
|
@resetErrors()
|
|
parsed = @parseId(e.id)
|
|
parsed.updating = false
|
|
|
|
if parsed['lesson-booking']
|
|
parsed.updating = true
|
|
rest.getLessonBooking({id: parsed.lesson_booking_id}).done((response) => @lessonBookingLoaded(response)).fail((jqXHR) => @failedLessonBooking(jqXHR))
|
|
else if parsed['teacher-intent']
|
|
parsed.updating = true
|
|
rest.getUserDetail({id: parsed.teacher_id}).done((response) => @teacherLoaded(response)).fail((jqXHR) => @failedTeacher(jqXHR))
|
|
else if parsed['test-drive']
|
|
logger.debug("test-drive lesson payment; no teacher/booking in context")
|
|
else if parsed['package-choice']
|
|
logger.debug("TestDrive package selected " + parsed.package_id)
|
|
rest.getTestDrivePackageChoice({id: parsed.package_id}).done((response) => @packageLoaded(response)).fail((jqXHR) => @failedPackage(jqXHR))
|
|
else
|
|
logger.error("unknown state for lesson-payment")
|
|
window.location.href = '/client#/jamclass'
|
|
|
|
@setState(parsed)
|
|
|
|
parseId: (id) ->
|
|
result = {}
|
|
|
|
# id can be:
|
|
# 'test-drive'
|
|
# or 'lesson-booking_id'
|
|
# or 'teacher_id
|
|
|
|
result['test-drive'] = false
|
|
result['lesson-booking'] = false
|
|
result['teacher-intent'] = false
|
|
result['package-choice'] = false
|
|
|
|
bits = id.split('_')
|
|
if bits.length == 1
|
|
# should be id=test-drive
|
|
result[id] = true
|
|
else if bits.length == 2
|
|
type = bits[0]
|
|
if type == 'lesson-booking'
|
|
result[type] = true
|
|
result.lesson_booking_id = bits[1]
|
|
else if type == 'teacher'
|
|
result['teacher-intent'] = true
|
|
result.teacher_id = bits[1]
|
|
else if type == 'package'
|
|
result['package-choice'] = true
|
|
result.package_id = bits[1]
|
|
|
|
logger.debug("LessonPayment: parseId " + JSON.stringify(result))
|
|
|
|
result
|
|
|
|
resetErrors: () ->
|
|
@setState({ccError: null, cvvError: null, expiryError: null, billingInUSError: null, zipCodeError: null, nameError: null})
|
|
|
|
checkboxChanged: (e) ->
|
|
checked = $(e.target).is(':checked')
|
|
|
|
@setState({billingInUS: checked})
|
|
|
|
resetState: () ->
|
|
@setState({updating: false, lesson: null, teacher: null, "test-drive": false, "lesson-booking" : false, "teacher-intent": false, package: null, "package-choice": null})
|
|
|
|
lessonBookingLoaded: (response) ->
|
|
@setState({updating: false})
|
|
logger.debug("lesson booking loaded", response)
|
|
|
|
if response.card_presumed_ok
|
|
context.JK.Banner.showNotice("Lesson Already Requested", "You have already requested this lesson from this teacher.")
|
|
window.location.href = "/client#/jamclass"
|
|
@setState({lesson: response, teacher: response.teacher})
|
|
|
|
failedLessonBooking: (jqXHR) ->
|
|
@setState({updating: false})
|
|
@app.layout.notify({
|
|
title: 'unable to load lesson info',
|
|
text: 'Something has gone wrong. Please try refreshing the page.'
|
|
})
|
|
|
|
teacherLoaded: (response) ->
|
|
@setState({updating: false})
|
|
logger.debug("teacher loaded", response)
|
|
@setState({teacher: response})
|
|
|
|
failedTeacher: (jqXHR) ->
|
|
@setState({updating: false})
|
|
@app.layout.notify({
|
|
title: 'unable to load teacher info',
|
|
text: 'Something has gone wrong. Please try refreshing the page.'
|
|
})
|
|
|
|
packageLoaded: (response) ->
|
|
@setState({updating: false})
|
|
logger.debug("package loaded", response)
|
|
@setState({package: response})
|
|
|
|
failedPackage: (jqXHR) ->
|
|
@setState({updating: false})
|
|
@app.layout.notify({
|
|
title: 'unable to load package info',
|
|
text: 'Something has gone wrong. Please try refreshing the page.'
|
|
})
|
|
|
|
onBack: (e) ->
|
|
e.preventDefault()
|
|
window.location.href = '/client#/teachers/search'
|
|
|
|
onSubmit: (e) ->
|
|
@resetErrors()
|
|
|
|
e.preventDefault()
|
|
|
|
if !window.Stripe?
|
|
logger.error("no window.Stripe")
|
|
@app.layout.notify({
|
|
title: 'Payment System Not Loaded',
|
|
text: "Please refresh this page and try to enter your info again. Sorry for the inconvenience!"
|
|
})
|
|
else
|
|
|
|
if @reuseStoredCard()
|
|
@attemptPurchase(null)
|
|
else
|
|
|
|
ccNumber = @root.find('input.card-number').val()
|
|
expiration = @root.find('input.expiration').val()
|
|
cvv = @root.find('input.cvv').val()
|
|
inUS = @root.find('input.billing-address-in-us').is(':checked')
|
|
zip = @root.find('input.zip').val()
|
|
|
|
error = false
|
|
|
|
|
|
if @state.shouldShowName
|
|
name = @root.find('#set-user-on-card').val()
|
|
|
|
if name.indexOf('Anonymous') > -1
|
|
@setState({nameError: true})
|
|
error = true
|
|
|
|
if !$.payment.validateCardNumber(ccNumber)
|
|
@setState({ccError: true})
|
|
error = true
|
|
|
|
bits = expiration.split('/')
|
|
|
|
if bits.length == 2
|
|
month = bits[0].trim();
|
|
year = bits[1].trim()
|
|
|
|
month = new Number(month)
|
|
year = new Number(year)
|
|
|
|
if year < 2000
|
|
year += 2000
|
|
|
|
if !$.payment.validateCardExpiry(month, year)
|
|
@setState({expiryError: true})
|
|
error = true
|
|
else
|
|
@setState({expiryError: true})
|
|
error = true
|
|
|
|
|
|
cardType = $.payment.cardType(ccNumber)
|
|
|
|
if !$.payment.validateCardCVC(cvv, cardType)
|
|
@setState({cvvError: true})
|
|
error = true
|
|
|
|
if inUS && (!zip? || zip == '')
|
|
@setState({zipCodeError: true})
|
|
|
|
if error
|
|
return
|
|
|
|
data = {
|
|
number: ccNumber,
|
|
cvc: cvv,
|
|
exp_month: month,
|
|
exp_year: year,
|
|
}
|
|
|
|
@setState({updating: true})
|
|
|
|
logger.debug("creating stripe token")
|
|
window.Stripe.card.createToken(data, (status, response) => (@stripeResponseHandler(status, response)));
|
|
|
|
stripeResponseHandler: (status, response) ->
|
|
console.log("stripe response", JSON.stringify(response))
|
|
|
|
if response.error
|
|
@setState({updating: false})
|
|
|
|
if response.error.code == "invalid_number"
|
|
@setState({ccError: true, cvvError: null, expiryError: null})
|
|
else if response.error.code == "invalid_cvc"
|
|
@setState({ccError: null, cvvError: true, expiryError: null})
|
|
else if response.error.code == "invalid_expiry_year" || response.error.code == "invalid_expiry_month"
|
|
@setState({ccError: null, cvvError: null, expiryError: true})
|
|
else
|
|
@attemptPurchase(response.id)
|
|
|
|
isNormal: () ->
|
|
@state.lesson?.lesson_type == 'paid'
|
|
|
|
isTestDrive: () ->
|
|
@state['test-drive'] == true || @state.lesson?.lesson_type == 'test-drive' || @state['teacher-intent'] || @state['package-choice'] == true
|
|
|
|
attemptPurchase: (token) ->
|
|
if this.state.billingInUS
|
|
zip = @root.find('input.zip').val()
|
|
|
|
data = {
|
|
token: token,
|
|
zip: zip,
|
|
test_drive: @isTestDrive(),
|
|
booking_id: @state.lesson?.id,
|
|
test_drive_package_choice_id: @state.package?.id
|
|
normal: @isNormal()
|
|
}
|
|
|
|
if @state.shouldShowName
|
|
data.name = @root.find('#set-user-on-card').val()
|
|
|
|
@setState({updating: true})
|
|
logger.debug("submitting purchase info: " + JSON.stringify(data))
|
|
rest.submitStripe(data).done((response) => @stripeSubmitted(response)).fail((jqXHR) => @stripeSubmitFailure(jqXHR))
|
|
|
|
stripeSubmitted: (response) ->
|
|
@setState({updating: false})
|
|
|
|
logger.debug("stripe submitted: " + JSON.stringify(response))
|
|
|
|
#if @state.shouldShowName
|
|
window.UserActions.refresh()
|
|
|
|
# if the response has a lesson, take them there
|
|
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
|
|
|
|
testDriveCount = response.lesson_package_type.package_type.substring(prefixLength, packageLength)
|
|
|
|
logger.debug("testDriveCount: " + testDriveCount)
|
|
|
|
testDriveCountInt = parseInt(testDriveCount);
|
|
if context._.isNaN(testDriveCountInt)
|
|
testDriveCountInt = 3
|
|
|
|
context.JK.GA.trackTestDrivePurchase(testDriveCountInt);
|
|
|
|
if response.test_drive?.teacher_id
|
|
teacher_id = response.test_drive.teacher_id
|
|
if testDriveCount == '1'
|
|
text = "You have purchased 1 TestDrive credit and have used it to request a JamClass with #{@state.package.teachers[0].user.name}. The teacher has received your request and should respond shortly."
|
|
else if response.package?
|
|
text = "Each teacher has received your request and should respond shortly."
|
|
else
|
|
text = "You have purchased #{testDriveCount} TestDrive credits and have used 1 credit to request a JamClass with #{@state.teacher.name}. The teacher has received your request and should respond shortly."
|
|
location = "/client#/jamclass"
|
|
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("TestDrive Purchased",text)
|
|
window.location = location
|
|
else
|
|
context.JK.Banner.showNotice("Something Went Wrong", "Please email support@jamkazam.com and indicate that your attempt to buy a TestDrive failed")
|
|
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 back to the JamClass home page, where you can check the status of this lesson, as well as any other past and future lessons.")
|
|
|
|
url = "/client#/jamclass/lesson-booking/" + response.lesson.id
|
|
url = "/client#/jamclass"
|
|
window.location.href = url
|
|
|
|
else
|
|
window.location = "/client#/teachers/search"
|
|
|
|
stripeSubmitFailure: (jqXHR) ->
|
|
logger.debug("stripe submission failure", jqXHR.responseText)
|
|
@setState({updating: false})
|
|
handled = false
|
|
if jqXHR.status == 422
|
|
errors = JSON.parse(jqXHR.responseText)
|
|
if errors.errors.name?
|
|
@setState({name: errors.errors.name[0]})
|
|
handled = true
|
|
else if errors.errors.user?
|
|
@app.layout.notify({title: "Can't Purchase Test Drive", text: "You " + errors.errors.user[0] + '.' })
|
|
handled = true
|
|
|
|
if !handled
|
|
@app.notifyServerError(jqXHR, 'Credit Card Not Stored')
|
|
|
|
onUnlockPaymentInfo: (e) ->
|
|
e.preventDefault()
|
|
@setState({userWantsUpdateCC: true})
|
|
|
|
onLockPaymentInfo: (e) ->
|
|
e.preventDefault()
|
|
@setState({userWantsUpdateCC: false})
|
|
|
|
reuseStoredCard: () ->
|
|
!@state.userWantsUpdateCC && @state.user?['has_stored_credit_card?']
|
|
|
|
bookedPrice: () ->
|
|
booked_price = this.state.lesson.booked_price
|
|
|
|
if booked_price?
|
|
if typeof booked_price == "string"
|
|
booked_price = new Number(booked_price)
|
|
return booked_price.toFixed(2)
|
|
else
|
|
return '??'
|
|
|
|
render: () ->
|
|
disabled = @state.updating || @reuseStoredCard()
|
|
|
|
if @state.updating
|
|
photo_url = '/assets/shared/avatar_generic.png'
|
|
name = 'Loading ...'
|
|
teacherDetails = `<div className="teacher-header">
|
|
<div className="avatar">
|
|
<img src={photo_url}/>
|
|
</div>
|
|
{name}
|
|
</div>`
|
|
else
|
|
if @state.lesson? || @state['test-drive'] || @state.teacher? || @state['package-choice'] == true
|
|
if @state.teacher?
|
|
photo_url = @state.teacher.photo_url
|
|
name = @state.teacher.name
|
|
|
|
if !photo_url?
|
|
photo_url = '/assets/shared/avatar_generic.png'
|
|
|
|
teacherDetails = `<div className="teacher-header">
|
|
<div className="avatar">
|
|
<img src={photo_url}/>
|
|
</div>
|
|
{name}
|
|
</div>`
|
|
else if @state.package?
|
|
teachers = []
|
|
teachersHolder = []
|
|
count = 0
|
|
for teacher_choice in @state.package.teachers
|
|
|
|
if count == 2
|
|
teachersHolder.push(
|
|
`<div className="teacher-holder">
|
|
{teachers}
|
|
</div>`)
|
|
teachers = []
|
|
teacher = teacher_choice.user
|
|
photo_url = teacher.photo_url
|
|
name = teacher.name
|
|
|
|
if !photo_url?
|
|
photo_url = '/assets/shared/avatar_generic.png'
|
|
|
|
teachers.push(
|
|
`<div key={teacher.id} className="teacher-subheader">
|
|
<div className="avatar">
|
|
<img src={photo_url}/>
|
|
</div>
|
|
<div className="teacher-name-packaged">{teacher.first_name}<br/>{teacher.last_name}</div>
|
|
</div>`)
|
|
count++
|
|
|
|
teachersHolder.push(
|
|
`<div className="teacher-holder">
|
|
{teachers}
|
|
</div>`)
|
|
teacherDetails = `<div className="teacher-header packaged">
|
|
{teachersHolder}
|
|
<br className="clearall" />
|
|
</div>`
|
|
|
|
if @state.lesson?
|
|
lesson_length = @state.lesson.lesson_length
|
|
lesson_type = @state.lesson.lesson_type
|
|
else
|
|
lesson_length = 30
|
|
lesson_type = 'test-drive'
|
|
|
|
|
|
|
|
if @isTestDrive()
|
|
|
|
if @reuseStoredCard()
|
|
header = `<div><h2>purchase test drive</h2></div>`
|
|
else
|
|
header = `<div><h2>enter payment info for test drive</h2></div>`
|
|
|
|
bookingInfo = `<p></p>`
|
|
if this.state['package-choice']
|
|
if this.state.package?
|
|
|
|
if @state.package.teachers.length == 1
|
|
explanation = `<span className="explanation">You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entities you to take a private online music lesson from this instructor. The price of this TestDrive is $14.99. If you have scheduling conflicts with this instructors, we will help you choose another teacher as a replacement.</span>`
|
|
else if @state.package.teachers.length == 2
|
|
explanation = `<span className="explanation">You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entities you to take 2 private online music lessons - 1 each from these 2 instructors. The price of this TestDrive is $29.99. If you have scheduling conflicts with any of these instructors, we will help you choose another teacher as a replacement.</span>`
|
|
else if @state.package.teachers.length == 4
|
|
explanation = `<span className="explanation">You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entities you to take 4 private online music lessons - 1 each from these 4 instructors. The price of this TestDrive is $49.99. If you have scheduling conflicts with any of these instructors, we will help you choose another teacher as a replacement.</span>`
|
|
else
|
|
alert("unknown package type")
|
|
else
|
|
if this.state.user.lesson_package_type_id == 'test-drive'
|
|
explanation = `<span>You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entitles you to take 4 private online music lessons - 1 each from 4 different instructors in the JamClass instructor community. The price of this TestDrive package is $49.99.</span>`
|
|
else if this.state.user.lesson_package_type_id == 'test-drive-1'
|
|
explanation =`<span>You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entitles you to take 1 private online music lesson from an instructor in the JamClass instructor community. The price of this TestDrive package is $14.99.</span>`
|
|
else if this.state.user.lesson_package_type_id == 'test-drive-2'
|
|
explanation =`<span>You are purchasing the TestDrive package of JamClass by JamKazam. This purchase entitles you to take 2 private online music lessons - 1 each from 2 different instructors in the JamClass instructor community. The price of this TestDrive package is $29.99.</span>`
|
|
else
|
|
alert("You do not have a test drive package selected: " + this.state.user.lesson_package_type_id )
|
|
|
|
|
|
bookingDetail = `<p>{explanation}
|
|
<br/>
|
|
|
|
<span className="jamclass-policies"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass
|
|
policies</a></span>
|
|
</p>`
|
|
else if @isNormal()
|
|
if @reuseStoredCard()
|
|
header = `<div><h2>purchase lesson</h2></div>`
|
|
else
|
|
header = `<div><h2>enter payment info for lesson</h2></div>`
|
|
|
|
if this.state.lesson.recurring
|
|
if this.state.lesson.payment_style == 'single'
|
|
bookingInfo = `<p>You are booking a {lesson_length} minute lesson for
|
|
${this.bookedPrice()}</p>`
|
|
bookingDetail = `<p>
|
|
Your card will not be charged until the day of the lesson. You must cancel at least 24 hours before your
|
|
lesson is scheduled, or you will be charged for the lesson in full.
|
|
<br/>
|
|
|
|
<span className="jamclass-policies"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass
|
|
policies</a></span>
|
|
</p>`
|
|
else if this.state.lesson.payment_style == 'weekly'
|
|
bookingInfo = `<p>You are booking a weekly recurring series of {lesson_length}-minute
|
|
lessons, to be paid individually as each lesson is taken, until cancelled.</p>`
|
|
bookingDetail = `<p>
|
|
Your card will be charged on the day of each lesson. If you need to cancel a lesson, you must do so at
|
|
least 24 hours before the lesson is scheduled, or you will be charged for the lesson in full.
|
|
<br/>
|
|
|
|
<span className="jamclass-policies"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass
|
|
policies</a></span>
|
|
</p>`
|
|
else if this.state.lesson.payment_style == 'monthly'
|
|
bookingInfo = `<p>You are booking a weekly recurring series of {lesson_length}-minute
|
|
lessons, to be paid for monthly until cancelled.</p>`
|
|
bookingDetail = `<p>
|
|
Your card will be charged on the first day of each month. Canceling individual lessons does not earn a
|
|
refund when buying monthly. To cancel, you must cancel at least 24 hours before the beginning of the
|
|
month, or you will be charged for that month in full.
|
|
<br/>
|
|
|
|
<span className="jamclass-policies"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass
|
|
policies</a></span>
|
|
</p>`
|
|
else
|
|
bookingInfo = `<p>You are booking a {lesson_length} minute lesson for
|
|
${this.bookedPrice()}</p>`
|
|
bookingDetail = `<p>
|
|
Your card will not be charged until the day of the lesson. You must cancel at least 24 hours before your
|
|
lesson is scheduled, or you will be charged for the lesson in full.
|
|
<br/>
|
|
|
|
<span className="jamclass-policies"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass
|
|
policies</a></span>
|
|
</p>`
|
|
else
|
|
if @reuseStoredCard()
|
|
header = `<div><h2>payment info already entered</h2></div>`
|
|
else
|
|
header = `<div><h2>enter payment info</h2></div>`
|
|
|
|
bookingInfo = `<p>You are entering your credit card info so that later checkouts go quickly. You can skip this
|
|
for now.</p>`
|
|
bookingDetail = `
|
|
<p>
|
|
Your card will not be charged until the day of the lesson. You must cancel at least 24 hours before your
|
|
lesson is scheduled, or you will be charged for the lesson in full.
|
|
<br/>
|
|
|
|
<span className="jamclass-policies plain"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass policies</a></span>
|
|
</p>`
|
|
|
|
|
|
submitClassNames = {'button-orange': true, 'purchase-btn': true, disabled: disabled && @state.updating}
|
|
updateCardClassNames = {'button-grey': true, disabled: disabled && @state.updating}
|
|
backClassNames = {'button-grey': true, disabled: disabled && @state.updating}
|
|
|
|
cardNumberFieldClasses = {field: true, "card-number": true, error: @state.ccError}
|
|
expirationFieldClasses = {field: true, "expiration": true, error: @state.expiryError}
|
|
cvvFieldClasses = {field: true, "card-number": true, error: @state.cvvError}
|
|
inUSClasses = {field: true, "billing-in-us": true, error: @state.billingInUSError}
|
|
zipCodeClasses = {field: true, "zip-code": true, error: @state.zipCodeError}
|
|
nameClasses= {field: true, "name": true, error: @state.nameError}
|
|
formClasses= {stored: @reuseStoredCard()}
|
|
leftColumnClasses = {column: true, 'column-left': true, stored: @reuseStoredCard()}
|
|
rightColumnClasses = {column: true, 'column-right': true, stored: @reuseStoredCard()}
|
|
|
|
if @state.user?['has_stored_credit_card?']
|
|
if @state.userWantsUpdateCC
|
|
updateCardAction = `<a className={classNames(updateCardClassNames)} onClick={this.onLockPaymentInfo}>NEVERMIND, USE MY STORED PAYMENT INFO</a>`
|
|
leftPurchaseActions = `<div className="actions">
|
|
<a className={classNames(backClassNames)} onClick={this.onBack}>BACK</a>
|
|
{updateCardAction}
|
|
<a className={classNames(submitClassNames)} onClick={this.onSubmit}>PURCHASE</a>
|
|
</div>`
|
|
else
|
|
updateCardAction = `<a className={classNames(updateCardClassNames)} onClick={this.onUnlockPaymentInfo}>I'D LIKE TO UPDATE MY PAYMENT INFO</a>`
|
|
rightPurchaseActions = `<div className="actions">
|
|
<a className={classNames(backClassNames)} onClick={this.onBack}>BACK</a>
|
|
{updateCardAction}
|
|
<a className={classNames(submitClassNames)} onClick={this.onSubmit}>PURCHASE</a>
|
|
</div>`
|
|
else
|
|
leftPurchaseActions = `<div className="actions">
|
|
<a className={classNames(backClassNames)} onClick={this.onBack}>BACK</a><a
|
|
className={classNames(submitClassNames)} onClick={this.onSubmit}>SUBMIT CARD INFORMATION</a>
|
|
</div>`
|
|
if @state.shouldShowName && @state.user?.name?
|
|
username = @state.user?.name
|
|
nameField =
|
|
`<div className={classNames(nameClasses)}>
|
|
<label>Name:</label>
|
|
<input id="set-user-on-card" disabled={disabled} type="text" name="name" className="name" defaultValue={username}></input>
|
|
</div>`
|
|
|
|
`<div className="content-body-scroller">
|
|
<div className={classNames(leftColumnClasses)}>
|
|
{header}
|
|
|
|
<form autoComplete="on" onSubmit={this.onSubmit} className={classNames(formClasses)}>
|
|
{nameField}
|
|
<div className={classNames(cardNumberFieldClasses)}>
|
|
<label>Card Number:</label>
|
|
<input placeholder="1234 5678 9123 4567" type="tel" autoComplete="cc-number" disabled={disabled}
|
|
type="text" name="card-number" className="card-number"></input>
|
|
</div>
|
|
<div className={classNames(expirationFieldClasses)}>
|
|
<label>Expiration Date:</label>
|
|
<input placeholder="MM / YY" autoComplete="cc-expiry" disabled={disabled} type="text" name="expiration"
|
|
className="expiration"></input>
|
|
</div>
|
|
<div className={classNames(cvvFieldClasses)}>
|
|
<label>CVV:</label>
|
|
<input autoComplete="off" disabled={disabled} type="text" name="cvv" className="cvv"></input>
|
|
</div>
|
|
<div className={classNames(zipCodeClasses)}>
|
|
<label>Zip Code</label>
|
|
<input autoComplete="off" disabled={disabled || !this.state.billingInUS} type="text" name="zip"
|
|
className="zip"></input>
|
|
</div>
|
|
<div className={classNames(inUSClasses)}>
|
|
<label>Billing Address<br/>is in the U.S.</label>
|
|
<input type="checkbox" name="billing-address-in-us" className="billing-address-in-us"
|
|
value={this.state.billingInUS}/>
|
|
</div>
|
|
<input style={{'display':'none'}} type="submit" name="submit"/>
|
|
</form>
|
|
{leftPurchaseActions}
|
|
</div>
|
|
<div className={classNames(rightColumnClasses)}>
|
|
{teacherDetails}
|
|
<div className="booking-info">
|
|
{bookingInfo}
|
|
{bookingDetail}
|
|
{rightPurchaseActions}
|
|
</div>
|
|
</div>
|
|
<br className="clearall"/>
|
|
|
|
</div>`
|
|
|
|
}) |