context = window rest = context.JK.Rest() logger = context.JK.logger UserStore = context.UserStore @LessonBooking = React.createClass({ mixins: [ Reflux.listenTo(AppStore, "onAppInit"), Reflux.listenTo(UserStore, "onUserChanged") ] onAppInit: (@app) -> @app.bindScreen('jamclass/lesson-booking', {beforeShow: @beforeShow, afterShow: @afterShow, beforeHide: @beforeHide, navName: 'Lesson Booking'}) onUserChanged: (userState) -> @setState({user: userState?.user}) onSlotDecision: (slot_decision) -> @setState({slot_decision: slot_decision?.slot_decision}) componentWillMount: () -> componentDidMount: () -> @checkboxes = [{selector: 'input.slot-decision', stateKey: 'slot-decision'}] @root = $(@getDOMNode()) componentDidUpdate: () -> # add friendly helpers to a slot processSlot: (slot, booking) -> if !slot? return slot.slotTime = @slotTime(slot, booking) slot.is_recurring = @isRecurring() if slot['is_teacher_created?'] slot.creatorRole = 'teacher' slot.creatorRoleRelative = 'teacher' else slot.creatorRole = 'student' slot.creatorRoleRelative = 'student' if context.JK.currentUserId == slot.proposer_id slot.creatorRoleRelative = "your" slot.mySlot = @mySlot(slot) componentWillUpdate: (nextProps, nextState) -> if nextState.booking? booking = nextState.booking if !booking.post_processed booking.post_processed = true for slot in booking.slots @processSlot(slot, booking) @processSlot(booking.counter_slot, booking) @processSlot(booking.default_slot, booking) @processSlot(booking.alt_slot, booking) getInitialState: () -> { user: null, booking: null, updating: false, updatingLesson: false } beforeHide: (e) -> beforeShow: (e) -> afterShow: (e) -> @setState({updating: true, counterErrors: null, cancelErrors: null}) rest.getLessonBooking({ id: e.id, }).done((response) => @getLessonBookingDone(response)).fail(@app.ajaxError) updateBookingState: (booking) -> if booking.counter_slot? startSlotDecision = booking.counter_slot.id else if booking.accepter_id? startSlotDecision = 'counter' else startSlotDecision = booking.default_slot.id @setState({booking: booking, updating: false, slot_decision: startSlotDecision, updatingLesson: false}) getLessonBookingDone: (response) -> @updateBookingState(response) toJamClassMain: (e) -> e.preventDefault() window.location.href = '/client#/jamclass' onCancel: () -> # what to do? window.location.href = '/client#/jamclass' onAccept: () -> @setState({updatingLesson: true, counterErrors: null, cancelErrors: null}) if @state.slot_decision == 'counter' request = @getSlotData(0) request.id = this.state.booking.id request.timezone = window.jstz.determine().name() request.message = @getMessage() request.update_all = true rest.counterLessonBooking(request).done((response) => @counterLessonBookingDone(response)).fail((response) => @counterLessonBookingFail(response)) else if @state.slot_decision == 'decline' request = {} request.message = @getMessage() request.id = this.state.booking.id request.update_all = true rest.cancelLessonBooking(request).done((response) => @cancelLessonBookingDone(response)).fail((response) => @cancelLessonBookingFail(response)) else if @state.slot_decision request = {} request.message = @getMessage() request.id = this.state.booking.id request.slot = this.state.slot_decision rest.acceptLessonBooking(request).done((response) => @acceptLessonBookingDone(response)).fail((response) => @acceptLessonBookingFail(response)) # {"errors":{"lesson_booking_slots":["is invalid"]},"_children":{"lesson_booking_slots":[{"errors":{}},{"errors":{}},{"errors":{"day_of_week":["must be specified"]}}]}} dayOfWeekMissing: (errors) -> console.log("errors", errors) childErrors = errors._children if childErrors for key, errorData of childErrors for slotErrors in errorData if slotErrors.errors?.day_of_week? return true return false acceptLessonBookingDone: (response ) -> logger.debug("accept lesson booking done") @updateBookingState(response) cancelLessonBookingDone: (response ) -> logger.debug("cancel lesson booking done") @updateBookingState(response) counterLessonBookingDone: (response ) -> logger.debug("counter lesson booking done") @updateBookingState(response) counterLessonBookingFail: (jqXHR ) -> @setState({updatingLesson: false}) logger.debug("counter lesson booking failed") handled = false if jqXHR.status == 422 errors = JSON.parse(jqXHR.responseText) if @dayOfWeekMissing(errors) handled = true @setState({counterErrors: {errors: {day_of_week: ["must be specified"]}}}) if !handled @app.ajaxError(arguments[0], arguments[1], arguments[2]) acceptLessonBookingFail: (response ) -> @setState({updatingLesson: false}) logger.debug("accept lesson booking failed", response) @app.ajaxError(arguments[0], arguments[1], arguments[2]) cancelLessonBookingFail: (jqXHR) -> @setState({updatingLesson: false}) logger.debug("cancel lesson booking failed", jqXHR) handled = false if jqXHR.status == 422 errors = JSON.parse(jqXHR.responseText) if errors.errors?.base? handled = true window.JK.Banner.showAlert("Unable to Cancel Lesson", errors.errors?.base[0]) if !handled @app.ajaxError(arguments[0], arguments[1], arguments[2]) getMessage: () -> @root.find('textarea.message').val() 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} student: () -> @state.booking?.user teacher: () -> @state.booking?.teacher otherRole: () -> if @teacherViewing() 'student' else 'teacher' other: () -> if @teacherViewing() @student() else if @studentViewing() @teacher() else null myself: () -> if @teacherViewing() @teacher() else if @studentViewing() @student() else null neverAccepted: () -> !this.state.booking?.accepter_id? defaultSlot: () -> @state.booking?.default_slot counteredSlot: () -> @state.booking?.counter_slot canceler: () -> if @student().id == this.state.booking?.canceler_id @student() else @teacher() counterer: () -> if @counteredSlot()?['is_teacher_created?'] @teacher() else @student() otherCountered: () -> @myself().id == @counterer().id studentCanceled: () -> @canceler().id == @student().id selfCanceled: () -> @canceler().id == @myself().id studentMadeDefaultSlot: () -> @student()?.id == @defaultSlot()?.proposer_id teacherViewing: () -> @state.booking? && @state.booking.teacher_id == context.JK.currentUserId studentViewing: () -> @state.booking? && @state.booking.user_id == context.JK.currentUserId isActive: () -> @state.booking?.active == true isRequested: () -> @state.booking?.status == 'requested' && !@isCounter() isCounter: () -> @counteredSlot()? && !@isCanceled() && !@isSuspended() isInitialCounter: () -> @isCounter() && !@isActive() isActiveCounter: () -> @isCounter() && @isActive() isApproved: () -> @state.booking?.status == 'approved' isCanceled: () -> @state.booking?.status == 'canceled' isSuspended: () -> @state.booking?.status == 'suspended' isStudentCountered: () -> @counteredSlot()?['is_student_created?'] isTeacherCountered: () -> @counteredSlot()?['is_teacher_created?'] isTestDrive: () -> @state.booking?.lesson_type == 'test-drive' isRecurring: (booking = this.state.booking) -> booking?.recurring lessonLength: () -> @state.booking?.lesson_length lessonDesc: () -> if @isRecurring() lessonType = "weekly recurring #{this.lessonLength()}-minute lesson" else lessonType = "single #{this.lessonLength()}-minute lesson" bookedPrice: () -> this.state.booking?.booked_price lessonPaymentAmt: () -> if @state.booking?.payment_style == 'elsewhere' '$10' else if @state.booking?.payment_style == 'single' "$#{this.bookedPrice()}" else if @state.booking?.payment_style == 'weekly' "at $#{this.bookedPrice()} per lesson" else if @state.booking?.payment_style == 'monthly' "monthly at $#{this.bookedPrice()} per month" else "$???" selfLastToAct: () -> if @isRequested() @studentViewing() else if @isCounter() @counterer().id == @myself().id else if @isCanceled() @canceler().id == @myself().id else if @isSuspended() @studentViewing() else false mySlot: (slot) -> slot.proposer_id == context.JK.currentUserId slotsDescription: (defaultSlot, altSlot) -> text = "Preferred day/time for lesson is #{this.slotTime(defaultSlot)}. Secondary option is #{this.slotTime(altSlot)}." slotTime: (slot, booking = this.state.booking) -> if @isRecurring(booking) "#{this.dayOfWeek(slot)} at #{this.dayTime(slot)}" else slot.pretty_start_time slotTimePhrase: (slot) -> if @isRecurring() "each " + @slotTime(slot) else @slotTime(slot) slotMessage: (slot, qualifier = '') -> @messageBlock(slot.mySlot,slot[qualifier + 'message'] ) messageBlock: (selfWroteMessage, message) -> if selfWroteMessage whoSaid = "You said:" else whoSaid = "Message from #{this.other().first_name}:" if message && message.length > 0 description = `
| {whoSaid} | {message} |
You should join this session immediately: {this.sessionLink()}
` else if @isPast() data =`This lesson is over.
` else data = `This lesson is scheduled to start at {this.state.booking.next_lesson.pretty_scheduled_start}
` else if @isRequested() data = `This lesson is scheduled to start at {this.state.booking.next_lesson.pretty_scheduled_start}
` `You should join this session immediately: {this.sessionLink()}
` else if @isPast() `This lesson is over.
` else `This lesson is scheduled to start at {this.state.booking.next_lesson.pretty_scheduled_start}
` else if @isRequested() `This lesson is scheduled to start at {this.state.booking.next_lesson.pretty_scheduled_start}
` renderCancelLesson: () -> `If you would like to cancel this lesson, you have to do so 24 hours in advance.
CANCEL LESSONYour {this.lessonDesc()} will take place each {this.slotTime(this.state.booking.default_slot)}
` else detail = `Your {this.lessonDesc()} will take place this {this.slotTime(this.state.booking.default_slot)}
` `Has accepted your lesson request.
{detail} {message}We strongly recommending adding this lesson to your calendar now so you don't forget it!
You can do this manually today; we will soon add a easier way to do so automatically.
{this.nextLessonSummary()}Message from {this.other().first_name}:
# renderStudentCountered: () -> @renderCountered() renderTeacherRequested: () -> if @isTestDrive() action = `Has requested a TestDrive {this.lessonLength()}-minute lesson, for which you will be paid $10.
` else action = `Has requested a {this.lessonDesc()} lesson, for which you will be paid {this.lessonPaymentAmt()}.
` `You canceled this lesson request.
` else action = `Has declined your lesson request.
` else if @studentCanceled() action = `Has canceled this lesson request.
` else action = `You declined this lesson request.
` if @studentViewing() if @studentCanceled() blurb = `We're sorry this scheduling attempt did not working out for you. Please search our community of instructors to find someone else who looks like a good fit for you, and submit a new lesson request
` else blurb = `We're sorry this instructor has declined your request. Please search our community of instructors to find someone else who looks like a good fit for you, and submit a new lesson request
` whatNow = `Has suggested a different time for your lesson.
` detail = `Proposed alternate day/time is {phrase}
` `