context = window rest = context.JK.Rest() logger = context.JK.logger UserStore = context.UserStore @BookLesson = React.createClass({ mixins: [ ICheckMixin, Reflux.listenTo(AppStore, "onAppInit"), Reflux.listenTo(UserStore, "onUserChanged") ] onAppInit: (@app) -> @app.bindScreen('jamclass/book-lesson', {beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide}) onUserChanged: (userState) -> @setState({user: userState?.user}) checkboxChanged: (e) -> checked = $(e.target).is(':checked') value = $(e.target).val() @setState({ recurring: value }) componentDidMount: () -> @checkboxes = [{selector: 'input.lesson-frequency', stateKey: 'lesson-frequency'}] @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)) }) @iCheckify() componentDidUpdate:() -> @iCheckify() @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) -> isNormal: () -> @state.type == 'normal' isTestDrive: () -> @state.type == 'test-drive' parseId:(id) -> if !id? {id: null, type: null} else bits = id.split('_') if bits.length == 2 {id: bits[1], type: bits[0]} else {id: null, type: null} beforeHide: (e) -> logger.debug("BookLesson: beforeHide") @resetErrors() beforeShow: (e) -> logger.debug("BookLesson: beforeShow", e.id) afterShow: (e) -> logger.debug("BookLesson: afterShow", e.id) parsed = @parseId(e.id) id = parsed.id @setState({teacherId: id, type: parsed.type}) @resetErrors() rest.getUserDetail({ id: 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("BookLesson: ignoring teacher details", response.id, @state.teacherId) getInitialState: () -> { user: null, teacher: null, teacherId: null, generalErrors: null, descriptionErrors: null, bookedPriceErrors: null, slot1Errors: null, slot2Errors: null updating: false, recurring: 'single' } jamclassPolicies: (e) -> e.preventDefault() context.JK.popExternalLink($(e.target).attr('href')) getSlotData: (position) -> $slot = @root.find('.slot-' + (position + 1)) picker = $slot.find('.date-picker') 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 else hour = null if minute? and minute != '' minute = new Number(minute) else minute = null if !@isRecurring() date = picker.datepicker("getDate") if date? date = context.JK.formatDateYYYYMMDD(date) else day_of_week = $slot.find('.day_of_week').val() {hour: hour, minute: minute, date: date, day_of_week: day_of_week} resetErrors: () -> @setState({generalErrors: null, slot1Errors: null, slot2Errors: null, descriptionErrors: null, bookedPriceErrors: null}) isRecurring: () -> @state.recurring == 'recurring' isMonthly: () -> if !@isRecurring() return false parsed = @bookingOption() return parsed? && parsed.frequency == 'monthly' bookingOption: () -> select = @root.find('.booking-options-for-teacher') value = select.val() @parseBookingOption(value) # select format = frequency|lesson_length , where frequency is 'monthly' or 'weekly' parseBookingOption: (value) -> if !value? return null bits = value.split('|') if !bits? || bits.length != 2 return null return {frequency: bits[0], lesson_length: bits[1]} onBookLesson: (e) -> e.preventDefault() if $(e.target).is('.disabled') return options = {} options.teacher = this.state.teacher.id options.slots = [@getSlotData(0), @getSlotData(1)] options.timezone = window.jstz.determine().name() description = @root.find('textarea.user-description').val() if description == '' description == null options.description = description if @isTestDrive() options.payment_style = 'elsewhere' options.lesson_type = 'test-drive' else if @isNormal() options.lesson_type = 'paid' if @isRecurring() if @isMonthly() options.payment_style = 'monthly' else options.payment_style = 'weekly' else options.payment_style = 'single' options.recurring = @isRecurring() parsed = @bookingOption() if parsed? options.lesson_length = parsed.lesson_length else throw "Unable to determine lesson type" @resetErrors() @setState({updating: true}) rest.bookLesson(options).done((response) => @booked(response)).fail((jqXHR) => @failedBooking(jqXHR)) booked: (response) -> @setState({updating: false}) if response.user['has_stored_credit_card?'] context.location ="/client#/jamclass/lesson-session/" + response.id else context.location = '/client#/jamclass/payment' failedBooking: (jqXHR) -> @setState({updating: false}) if jqXHR.status == 422 body = JSON.parse(jqXHR.responseText) generalErrors = {errors: {}} for errorType, errors of body.errors if errorType == 'description' @setState({descriptionErrors: errors}) else if errorType == 'booked_price' @setState({bookedPriceErrors: errors}) else if errorType == 'lesson_length' # swallow, because 'booked_price' covers this else if errorType == 'lesson_booking_slots' # do nothing. these are handled better by the _children errors else generalErrors.errors[errorType] = 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}) if Object.keys(slot2Errors["errors"]).length > 0 @setState({slot2Errors: slot2Errors}) if Object.keys(generalErrors.errors).length > 0 @setState({generalErrors: generalErrors}) onCancel: (e) -> e.preventDefault() isTestDrive: () -> @state.type == 'test-drive' isNormal: () -> @state.type == 'normal' constructBookingOptions: () -> results = [] if !@state.teacher? return results teacher = @state.teacher.teacher enabledMinutes = [] for minutes in [30, 45, 60, 90, 120] duration_enabled = teacher["lesson_duration_#{minutes}"] if duration_enabled enabledMinutes.push(minutes) if !@isRecurring() for minutes in enabledMinutes lesson_price = teacher["price_per_lesson_#{minutes}_cents"] value = "single|#{minutes}" display = "#{minutes} Minute Lesson for $#{(lesson_price / 100).toFixed(2)}" results.push(``) else for minutes in enabledMinutes lesson_price = teacher["price_per_lesson_#{minutes}_cents"] value = "single|#{minutes}" display = "#{minutes} Minute Lesson Each Week - $#{(lesson_price / 100).toFixed(2)} Per Week" results.push(``) for minutes in enabledMinutes monthly_price = teacher["price_per_month_#{minutes}_cents"] value = "monthly|#{minutes}" display = "#{minutes} Minute Lesson Each Week - $#{(monthly_price / 100).toFixed(2)} Per Month" results.push(``) if results.length == 0 results.push(``) else results.unshift(``) results render: () -> photo_url = teacher?.photo_url if !photo_url? photo_url = '/assets/shared/avatar_generic.png' teacher = @state.teacher if teacher? name = `
{teacher.name}
` teacher_first_name = teacher.first_name else name = `
Loading...
` teacher_first_name = '...' hours = [] for hour in ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] if hour == '12' key = '00' else key = hour hours.push(``) minutes = [] for minute in ['00', '15', '30', '45'] minutes.push(``) am_pm = [``, ``] bookLessonClasses = classNames({"button-orange": true, disabled: !this.state.teacher? && !@state.updating}) cancelClasses = classNames({"button-grey": true, disabled: !this.state.teacher? && !@state.updating}) descriptionErrors = context.JK.reactSingleFieldErrors('description', @state.descriptionErrors) bookedPriceErrors = context.JK.reactSingleFieldErrors('booked_price', @state.bookedPriceErrors) slot1Errors = context.JK.reactErrors(@state.slot1Errors, {preferred_day: 'Date', day_of_week: 'Day'}) slot2Errors = context.JK.reactErrors(@state.slot2Errors, {preferred_day: 'Date', day_of_week: 'Day'}) generalErrors = context.JK.reactErrors(@state.generalErrors, {user: 'You'}) bookedPriceClasses = classNames({booked_price: true, error: bookedPriceErrors?, field: true, 'booking-options': true}) descriptionClasses = classNames({description: true, error: descriptionErrors?}) slot1Classes = classNames({slot: true, 'slot-1': true, error: slot1Errors?}) slot2Classes = classNames({slot: true, 'slot-2': true, error: slot2Errors?}) generalClasses = classNames({general: true, error: generalErrors?}) if !@isRecurring() slots = `
What date/time do you prefer for your lesson?
:
{slot1Errors}
What is a second date/time option if preferred not available?
:
{slot2Errors}
` else days = [] days.push(``) days.push(``) days.push(``) days.push(``) days.push(``) days.push(``) days.push(``) days.push(``) slots = `
What day/time do you prefer for your lesson?
:
{slot1Errors}
What is a second day/time option if preferred not available?
:
{slot2Errors}
` if @isTestDrive() header = `

book testdrive lesson

` if @state.user?.remaining_test_drives == 1 testDriveLessons = "1 TestDrive lesson credit" else testDriveLessons = "#{this.state.user?.remaining_test_drives} TestDrive lesson credits" actions = `
CANCEL BOOK TESTDRIVE LESSON
` columnLeft = `
{header} {slots}
Tell {teacher_first_name} a little about yourself as a student.