258 lines
8.2 KiB
CoffeeScript
258 lines
8.2 KiB
CoffeeScript
context = window
|
|
rest = context.JK.Rest()
|
|
logger = context.JK.logger
|
|
|
|
UserStore = context.UserStore
|
|
AppStore = context.AppStore
|
|
ProfileActions = context.ProfileActions
|
|
|
|
profileUtils = context.JK.ProfileUtils
|
|
|
|
proficiencyCssMap = {
|
|
"1": "proficiency-beginner",
|
|
"2": "proficiency-intermediate",
|
|
"3": "proficiency-expert"
|
|
};
|
|
|
|
proficiencyDescriptionMap = {
|
|
"1": "BEGINNER",
|
|
"2": "INTERMEDIATE",
|
|
"3": "EXPERT"
|
|
};
|
|
|
|
@BookLessonFree = React.createClass({
|
|
|
|
mixins: [
|
|
Reflux.listenTo(AppStore, "onAppInit"),
|
|
Reflux.listenTo(UserStore, "onUserChanged")
|
|
]
|
|
|
|
onAppInit: (@app) ->
|
|
@app.bindScreen('jamclass/book-lesson-free',
|
|
{beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide})
|
|
|
|
componentDidMount: () ->
|
|
@root = $(@getDOMNode())
|
|
|
|
@slot1Date = @root.find('.slot-1 .date-picker')
|
|
@slot2Date = @root.find('.slot-2 .date-picker')
|
|
@slot1Date.datepicker({
|
|
dateFormat: "D M d yy",
|
|
onSelect: ((e) => @toggleDate(e))
|
|
})
|
|
@slot2Date.datepicker({
|
|
dateFormat: "D M d yy",
|
|
onSelect: ((e) => @toggleDate(e))
|
|
})
|
|
|
|
toggleDate: (e) ->
|
|
|
|
beforeHide: (e) ->
|
|
logger.debug("LessonBookingFree: beforeHide")
|
|
|
|
beforeShow: (e) ->
|
|
logger.debug("LessonBookingFree: beforeShow", e.id)
|
|
|
|
afterShow: (e) ->
|
|
logger.debug("LessonBookingFree: afterShow", e.id)
|
|
@setState({teacherId: e.id})
|
|
rest.getUserDetail({
|
|
id: e.id,
|
|
show_teacher: true
|
|
}).done((response) => @userDetailDone(response)).fail(@app.ajaxError)
|
|
|
|
userDetailDone: (response) ->
|
|
if response.id == @state.teacherId
|
|
@setState({teacher: response, isSelf: response.id == context.JK.currentUserId})
|
|
else
|
|
logger.debug("BookLessonFree: ignoring teacher details", response.id, @state.teacherId)
|
|
|
|
getInitialState: () ->
|
|
{
|
|
teacher: null,
|
|
teacherId: null,
|
|
generalErrors: []
|
|
}
|
|
|
|
onUserChanged: (userState) ->
|
|
@user = userState?.user
|
|
|
|
jamclassPolicies: (e) ->
|
|
e.preventDefault()
|
|
context.JK.popExternalLink($(e.target).attr('href'))
|
|
|
|
getSlotData: (position) ->
|
|
$slot = @root.find('.slot-' + (position + 1))
|
|
picker = $slot.find('.date-picker')
|
|
|
|
date = picker.datepicker("getDate")
|
|
hour = $slot.find('.hour').val()
|
|
minute = $slot.find('.minute').val()
|
|
am_pm = $slot.find('.am_pm').val()
|
|
|
|
if hour? and hour != ''
|
|
hour = new Number(hour)
|
|
if am_pm == 'PM'
|
|
hour += 12
|
|
hour -= 1
|
|
else
|
|
hour = null
|
|
|
|
if minute? and minute != ''
|
|
minute = new Number(minute)
|
|
else
|
|
minute = null
|
|
|
|
day = null
|
|
if date?
|
|
day = context.JK.formatDateYYYYMMDD(date)
|
|
|
|
logger.debug("slot #{position} has day #{day} at time #{hour}:#{minute}")
|
|
|
|
{hour: hour, minute: minute, day: day}
|
|
|
|
onBookFreeLesson: (e) ->
|
|
e.preventDefault()
|
|
|
|
options = {}
|
|
options.teacher = this.state.teacher.id
|
|
options.payment_style = 'elsewhere'
|
|
options.lesson_type = 'single-free'
|
|
options.slots = [@getSlotData(0), @getSlotData(1)]
|
|
description = @root.find('textarea.user-description').val()
|
|
if description == ''
|
|
description == null
|
|
options.description = description
|
|
|
|
rest.bookLesson(options).done((response) => @booked(response)).fail((jqXHR) => @failedBooking(jqXHR))
|
|
|
|
booked: (response) ->
|
|
if response.user['has_stored_credit_card?']
|
|
context.location '/client#/home'
|
|
else
|
|
context.location = '/client#/jamclass/payment'
|
|
|
|
resetErrors: () ->
|
|
@setState({generalErrors:null, slot1Errors:null, slot2Errors:null, descriptionError:null})
|
|
failedBooking: (jqXHR) ->
|
|
if jqXHR.status == 422
|
|
body = JSON.parse(jqXHR.responseText)
|
|
|
|
generalErrors = []
|
|
for errorType, errors of body.errors
|
|
if errorType == 'description'
|
|
@setState({descriptionError: errors})
|
|
else
|
|
error = {}
|
|
error[errorType] = errors
|
|
generalErrors.push(errors)
|
|
|
|
for childErrorType, childErrors of body._children
|
|
if childErrorType == 'lesson_booking_slots'
|
|
slot1Errors = childErrors[0]
|
|
slot2Errors = childErrors[1]
|
|
if Object.keys(slot1Errors["errors"]).length > 0
|
|
@setState({slot1Errors: slot1Errors["errors"]})
|
|
if Object.keys(slot2Errors["errors"]).length > 0
|
|
@setState({slot2Errors: slot2Errors["errors"]})
|
|
if childErrors.length > 0
|
|
@setState({childErrorType, childErrors})
|
|
@setState({generalErrors: generalErrors})
|
|
|
|
onCancel: (e) ->
|
|
e.preventDefault()
|
|
|
|
render: () ->
|
|
photo_url = teacher?.photo_url
|
|
if !photo_url?
|
|
photo_url = '/assets/shared/avatar_generic.png'
|
|
|
|
teacher = @state.teacher
|
|
|
|
if teacher?
|
|
name = `<div className="teacher-name">{teacher.name}</div>`
|
|
teacher_first_name = teacher.first_name
|
|
else
|
|
name = `<div className="teacher-name">Loading...</div>`
|
|
teacher_first_name = '...'
|
|
|
|
hours = []
|
|
for hour in ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12']
|
|
hours.push(`<option key={hour} value={hour}>{hour}</option>`)
|
|
|
|
minutes = []
|
|
for minute in ['00', '15', '30', '45']
|
|
minutes.push(`<option key={minute} value={minute}>{minute}</option>`)
|
|
|
|
am_pm = [`<option key="AM" value="AM">AM</option>`, `<option key="PM" value="PM">PM</option>`]
|
|
|
|
bookLessonClasses = classNames({"button-orange": true, disabled: !this.state.teacher?})
|
|
cancelClasses = classNames({"button-grey": true, disabled: !this.state.teacher?})
|
|
`<div className="content-body-scroller">
|
|
<div className="lesson-booking">
|
|
<div className="column column-left">
|
|
<h2>book free lesson</h2>
|
|
|
|
<div className="slots">
|
|
<div className="slot slot-1">
|
|
<div className="slot-prompt">What date/time do you prefer for your lesson?</div>
|
|
<div className="field date">
|
|
<label>Date:</label>
|
|
|
|
<input className="date-picker" type="text" data-slot="1"></input>
|
|
</div>
|
|
<div className="field time">
|
|
<label>Time:</label>
|
|
<select className="hour">{hours}</select> : <select className="minute">{minutes}</select> <select
|
|
className="am_pm">{am_pm}</select>
|
|
</div>
|
|
</div>
|
|
<div className="slot slot-2">
|
|
<div className="slot-prompt">What is a second date/time option if preferred not available?</div>
|
|
<div className="field date">
|
|
<label>Date:</label>
|
|
|
|
<input className="date-picker" type="text" data-slot="2"></input>
|
|
</div>
|
|
<div className="field time">
|
|
<label>Time:</label>
|
|
<select className="hour">{hours}</select> : <select className="minute">{minutes}</select> <select
|
|
className="am_pm">{am_pm}</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="description">
|
|
<div className="description-prompt">Tell {teacher_first_name} a little about yourself as a student.</div>
|
|
<textarea className="user-description" defaultValue=""/>
|
|
</div>
|
|
</div>
|
|
<div className="column column-right">
|
|
<div className="teacher-header">
|
|
<div className="avatar">
|
|
<img src={photo_url}/>
|
|
</div>
|
|
{name}
|
|
</div>
|
|
<div className="booking-info">
|
|
<p>You are purchasing a single free 30-minute JamClass session.</p>
|
|
|
|
<p>To book this lesson, you will need to enter your credit card information.
|
|
You will absolutely not be charged for this free lesson, and you have no further
|
|
commitment to purchase anything. We have to collect a credit card to prevent abuse
|
|
by some users who would otherwise set up multiple free accounts to get multiple free lessons.<br/>
|
|
|
|
<div className="jamclass-policies"><a href="/corp/terms" rel="external" onClick={this.jamclassPolicies}>jamclass
|
|
policies</a></div>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<br className="clearall"/>
|
|
|
|
<div className="actions">
|
|
<a className={bookLessonClasses} onClick={this.onBookFreeLesson}>BOOK FREE LESSON</a>
|
|
<a className={cancelClasses} onClick={this.onCancel}>CANCEL</a>
|
|
</div>
|
|
</div>
|
|
</div>`
|
|
}) |