context = window
rest = context.JK.Rest()
logger = context.JK.logger
UserStore = context.UserStore
@LessonBooking = React.createClass({
mixins: [
@PostProcessorMixin,
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})
onUpdateAllDecision: (update_all) ->
@setState({update_all: update_all?.update_all})
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)
hasFocusedLesson: () ->
this.state.booking.focused_lesson?.id?
focusedLesson: () ->
this.state?.booking?.focused_lesson
updateBookingState: (booking) ->
console.log("updating booking state", booking)
if booking.counter_slot?
startSlotDecision = booking.counter_slot.id
else
if booking.accepter_id?
startSlotDecision = 'counter'
else
startSlotDecision = booking.default_slot.id
update_all = !booking.focused_lesson?.id?
if booking.focused_lesson?
#booking.focused_lesson.lesson_booking = booking
@postProcessLesson(booking.focused_lesson)
if booking.next_lesson?
#booking.next_lesson.lesson_booking = booking
@postProcessLesson(booking.next_lesson)
@setState({booking: booking, updating: false, slot_decision: startSlotDecision, updatingLesson: false, update_all: update_all})
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.lesson_session_id = @focusedLesson()?.id
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.lesson_session_id = @focusedLesson()?.id
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)
window.location.href = '/client#/jamclass'
cancelLessonBookingDone: (response ) ->
context.JK.Banner.showNotice("Lesson Canceled", "Your lesson has been canceled.
We've taken you back to the JamClass home page.")
logger.debug("cancel lesson booking done")
@updateBookingState(response)
window.location.href = '/client#/jamclass'
counterLessonBookingDone: (response ) ->
context.JK.Banner.showNotice("Lesson Change Requested", "Your request for a time has been sent.
We've taken you back to the JamClass home page.")
logger.debug("counter lesson booking done")
@updateBookingState(response)
window.location.href = '/client#/jamclass'
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.responseText)
@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()
update_all = $slot.find('input.update-all').is(':checked') && @isRecurring()
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, update_all: update_all}
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: () ->
!@studentViewing()
studentViewing: () ->
@state.booking? && @state.booking.user_id == context.JK.currentUserId
isActive: () ->
@state.booking?.active == true
isRequested: () ->
@state.booking?.status == 'requested' && !@isCounter()
isSuccessful: () ->
@displayableLesson().success
isCounter: () ->
@counteredSlot()? && !@isCanceled() && !@isSuspended()
isInitialCounter: () ->
@isCounter() && !@isActive()
isActiveCounter: () ->
@isCounter() && @isActive()
isCompleted: () ->
if @state.booking?
@displayableLesson().status == 'completed'
else
false
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: () ->
price = this.state.booking?.booked_price
if price?
if typeof price == "string"
price = new Number(price)
return price.toFixed(2)
else
return price
lessonPaymentAmt: () ->
console.log("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.displayableLesson().pretty_scheduled_start}
` else if @isRequested() data = `This lesson is scheduled to start at {this.displayableLesson().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.displayableLesson().pretty_scheduled_start}
` else if @isRequested() `This lesson is scheduled to start at {this.displayableLesson().pretty_scheduled_start}
` renderCancelLesson: () -> `If you would like to cancel this lesson, you have to do so 24 hours in advance.
CANCEL LESSONThis lesson was missed by the {this.displayableLesson().missedRole}.
You should update your credit card info. update credit card
Your {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)}
` summary = `Has accepted your lesson request.
{detail} {message}You should join the lesson session as soon as possible. join session now
{this.nextLessonSummary()}Your {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)}
` summary = `Has accepted your lesson request.
{detail} {message}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()}.
` `This lesson was missed by the {this.displayableLesson().missedRole}.
You should update your credit card info. update credit card
Your {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)}
` summary = `Is ready to take the lesson.
{detail} {message}You should join the lesson session as soon as possible. join session now
{this.nextLessonSummary()}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}
` `