2016-04-06 02:23:15 +00:00
context = window
rest = context . JK . Rest ( )
logger = context . JK . logger
UserStore = context . UserStore
@LessonBooking = React . createClass ( {
mixins: [
2016-05-19 18:26:37 +00:00
@ PostProcessorMixin ,
2016-04-06 02:23:15 +00:00
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 } )
2016-04-21 14:23:29 +00:00
onUpdateAllDecision: (update_all) ->
@ setState ( { update_all: update_all ? . update_all } )
2016-04-06 02:23:15 +00:00
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 )
2017-07-10 02:21:29 +00:00
slot.is_recurring = slot . slot_type == ' recurring '
2016-04-06 02:23:15 +00:00
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 )
2016-06-03 04:32:09 +00:00
# for a test drive packaged delai, while we do create a slot to satisfy certain aspects of the backend, it's not 'real'. So we say 'noSlots' until someone has proposed something
noSlots: () ->
@ state . booking ? . no_slots
2016-05-30 21:43:55 +00:00
processBooking : (booking) ->
booking.neverAccepted = booking . accepter_id ?
booking.isCounter = booking . counter_slot ? && booking . status != ' canceled ' && booking . status != ' suspended '
booking.studentViewing = booking . user_id == context . JK . currentUserId
booking.teacherViewing = ! booking . studentViewing
booking.isRequested = booking . status == ' requested ' && ! booking . isCounter
booking.isCanceled = booking . status == ' canceled '
booking.isSuspended = booking . status == ' suspended '
2016-06-03 04:32:09 +00:00
2016-05-30 21:43:55 +00:00
if booking . isCounter
if booking . counter_slot [ ' is_teacher_created? ' ]
booking.countererId = booking . teacher_id
else
booking.countererId = booking . user_id
selfLastToAct = false
if booking . isRequested
selfLastToAct = booking . studentViewing
else if booking . isCounter
selfLastToAct = booking . countererId == context . JK . currentUserId
else if booking . isCanceled
selfLastToAct = booking . canceler_id == context . JK . currentUserId
else if booking . isSuspended
selfLastToAct = booking . studentViewing
else
selfLastToAct = false
booking.selfLastToAct = selfLastToAct
multipleOptions = false
if booking . neverAccepted
multipleOptions = ! ( ! booking . isCounter && booking . selfLastToAct )
else if booking . isCounter
multipleOptions = ! booking . selfLastToAct
else
multipleOptions = false
onlyOption = ! multipleOptions
booking.onlyOption = onlyOption
#nextProps.slot_decision = 'counter'
2016-04-06 02:23:15 +00:00
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 )
2017-07-17 00:38:40 +00:00
if booking . focused_lesson ?
@ processSlot ( booking . focused_lesson . counter_slot , booking )
2016-04-06 02:23:15 +00:00
2016-05-30 21:43:55 +00:00
onlyOption : () ->
#(this.props.initial && !this.props.selfLastToAct )|| !(this.props.counter && !this.props.selfLastToAct)
#@initialRequestSlotsVisible() || !@counteredSlotVisible()
#(this.props.initial && this.props.selfLastToAct ) || !(this.props.counter && !this.props.selfLastToAct)
#(@neverAccepted() && @selfLastToAct()) || !(@isCounter() && !@selfLastToAct())
! @ multipleOptions ( )
multipleOptions: () ->
if @ neverAccepted ( )
! ( ! @ isCounter ( ) && @ selfLastToAct ( ) )
else if this . props . counter
! @ selfLastToAct ( )
else
false
initialRequestSlotsVisible: () ->
console . log ( " initialRequestSlotsVisible: " + this . neverAccepted ( ) )
#this.neverAccepted() && this.selfLastToAct()
# is there a counter slot showing
counteredSlotVisible: () ->
console . log ( " isCounter " + this . isCounter ( ) + " , this.selfLastToAct() " + this . selfLastToAct ( ) )
this . isCounter ( ) && ! this . selfLastToAct ( )
counterSlotVisible: () ->
true
2016-04-06 02:23:15 +00:00
getInitialState: () ->
{
user: null ,
booking: null ,
updating: false ,
updatingLesson: false
}
beforeHide: (e) ->
beforeShow: (e) ->
2016-05-30 21:43:55 +00:00
parseId: (id) ->
result = { purpose: null }
bits = id . split ( ' _ ' )
if bits . length == 1
result.id = id
else if bits . length > 1
result . id = bits [ 0 ]
result.purpose = bits [ 1 ]
else
result.id = id
result
2016-04-06 02:23:15 +00:00
afterShow: (e) ->
2016-05-30 21:43:55 +00:00
parsed = @ parseId ( e . id )
@ setState ( { updating: true , counterErrors: null , cancelErrors: null , purpose: parsed . purpose } )
2016-04-06 02:23:15 +00:00
rest . getLessonBooking ( {
2016-05-30 21:43:55 +00:00
id: parsed . id ,
2016-04-06 02:23:15 +00:00
} ) . done ( (response) => @ getLessonBookingDone ( response ) ) . fail ( @ app . ajaxError )
2017-07-17 00:38:40 +00:00
hasFocusedLesson: (booking = this.state?.booking) ->
@ focusedLesson ( booking ) ?
2016-04-21 14:23:29 +00:00
2017-07-17 00:38:40 +00:00
focusedLesson: (booking = this.state?.booking) ->
booking ? . focused_lesson
2016-04-21 14:23:29 +00:00
2016-04-06 02:23:15 +00:00
updateBookingState: (booking) ->
2016-04-21 14:23:29 +00:00
console . log ( " updating booking state " , booking )
2017-07-17 00:38:40 +00:00
slot_update_all = false
counter_slot = @ counteredSlot ( booking )
if counter_slot ?
startSlotDecision = counter_slot . id
slot_update_all = counter_slot [ ' is_recurring? ' ]
2016-04-06 02:23:15 +00:00
else
2016-05-31 13:35:04 +00:00
if booking . accepter_id ?
startSlotDecision = ' counter '
else
startSlotDecision = booking . default_slot . id
2017-07-17 00:38:40 +00:00
slot_update_all = booking . default_slot [ ' is_recurring? ' ]
2016-04-06 02:23:15 +00:00
2017-07-17 00:38:40 +00:00
update_all = slot_update_all || ! booking . focused_lesson ? . id ?
2016-04-21 14:23:29 +00:00
2016-05-19 18:26:37 +00:00
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 )
2016-05-30 21:43:55 +00:00
@ processBooking ( booking )
2016-05-31 13:35:04 +00:00
if booking . onlyOption
2016-05-30 21:43:55 +00:00
# you see two options (accept, and propose new) if it's a counter and you are not the last to act
# the only choice possible in most cases is to propose a new time
2016-05-31 13:35:04 +00:00
#nextState.slot_decision = 'counter'
startSlotDecision = ' counter '
2016-04-21 14:23:29 +00:00
@ setState ( { booking: booking , updating: false , slot_decision: startSlotDecision , updatingLesson: false , update_all: update_all } )
2016-04-06 02:23:15 +00:00
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 ( )
2016-04-21 14:23:29 +00:00
request.lesson_session_id = @ focusedLesson ( ) ? . id
2016-04-06 02:23:15 +00:00
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
2016-04-21 14:23:29 +00:00
request.lesson_session_id = @ focusedLesson ( ) ? . id
2016-04-06 02:23:15 +00:00
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
2017-03-22 12:39:06 +00:00
request.lesson_session_id = @ focusedLesson ( ) ? . id
2016-04-06 02:23:15 +00:00
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 )
2016-05-19 19:12:43 +00:00
window . location.href = ' /client # /jamclass '
2016-04-06 02:23:15 +00:00
cancelLessonBookingDone: (response ) ->
2016-05-19 19:12:43 +00:00
context . JK . Banner . showNotice ( " Lesson Canceled " , " Your lesson has been canceled.<br/><br/>We ' ve taken you back to the JamClass home page. " )
2016-04-06 02:23:15 +00:00
logger . debug ( " cancel lesson booking done " )
@ updateBookingState ( response )
2016-05-19 19:12:43 +00:00
window . location.href = ' /client # /jamclass '
2016-04-06 02:23:15 +00:00
counterLessonBookingDone: (response ) ->
2016-05-19 19:12:43 +00:00
context . JK . Banner . showNotice ( " Lesson Change Requested " , " Your request for a time has been sent.<br/><br/>We ' ve taken you back to the JamClass home page. " )
2016-04-06 02:23:15 +00:00
logger . debug ( " counter lesson booking done " )
@ updateBookingState ( response )
2016-05-19 19:12:43 +00:00
window . location.href = ' /client # /jamclass '
2016-04-06 02:23:15 +00:00
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 } )
2016-05-16 16:39:20 +00:00
logger . debug ( " accept lesson booking failed " + response . responseText )
2016-04-06 02:23:15 +00:00
@ 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 ( )
2016-05-30 21:43:55 +00:00
#update_all = $slot.find('input.update-all').is(':checked') && @isRecurring()
update_all = @ state . update_all && @ isRecurring ( )
2016-04-06 02:23:15 +00:00
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
2016-05-30 21:43:55 +00:00
if ! update_all
2016-04-06 02:23:15 +00:00
date = picker . datepicker ( " getDate " )
if date ?
date = context . JK . formatDateYYYYMMDD ( date )
else
day_of_week = $slot . find ( ' .day_of_week ' ) . val ( )
2016-04-21 14:23:29 +00:00
{ hour: hour , minute: minute , date: date , day_of_week: day_of_week , update_all: update_all }
2016-04-06 02:23:15 +00:00
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
2017-07-17 00:38:40 +00:00
counteredSlot: (booking = @state.booking) ->
slot = null
if @ hasFocusedLesson ( booking )
focused = @ focusedLesson ( booking )
if focused . status == ' countered '
slot = focused . counter_slot
if ! slot ?
# only consider the booking slot if it's present and if it's marked is_recurring?
if booking ? . counter_slot ? [ ' is_recurring? ' ]
slot = booking ? . counter_slot
slot
2016-04-06 02:23:15 +00:00
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
2018-01-27 22:18:04 +00:00
adminCanceled: () ->
this . state . booking ? . canceled_by_admin ?
2016-04-06 02:23:15 +00:00
studentCanceled: () ->
2018-01-27 22:18:04 +00:00
@ canceler ( ) ? . id == @ student ( ) . id
2016-04-06 02:23:15 +00:00
selfCanceled: () ->
2018-01-27 22:18:04 +00:00
@ canceler ( ) ? . id == @ myself ( ) . id
2016-04-06 02:23:15 +00:00
studentMadeDefaultSlot: () ->
@ student ( ) ? . id == @ defaultSlot ( ) ? . proposer_id
teacherViewing: () ->
2016-05-19 18:26:37 +00:00
! @ studentViewing ( )
2016-04-06 02:23:15 +00:00
studentViewing: () ->
@ state . booking ? && @ state . booking . user_id == context . JK . currentUserId
isActive: () ->
@ state . booking ? . active == true
isRequested: () ->
@ state . booking ? . status == ' requested ' && ! @ isCounter ( )
2016-05-19 18:26:37 +00:00
isSuccessful: () ->
@ displayableLesson ( ) . success
2016-04-06 02:23:15 +00:00
isCounter: () ->
@ counteredSlot ( ) ? && ! @ isCanceled ( ) && ! @ isSuspended ( )
isInitialCounter: () ->
@ isCounter ( ) && ! @ isActive ( )
isActiveCounter: () ->
@ isCounter ( ) && @ isActive ( )
2016-05-19 18:26:37 +00:00
isCompleted: () ->
if @ state . booking ?
@ displayableLesson ( ) . status == ' completed '
else
false
2016-04-06 02:23:15 +00:00
isApproved: () ->
2017-07-10 02:21:29 +00:00
if @ hasFocusedLesson ( )
@ focusedLesson ( ) . status == ' approved '
else
@ state . booking ? . status == ' approved '
2016-04-06 02:23:15 +00:00
isCanceled: () ->
2017-07-10 02:21:29 +00:00
cancelled = @ state . booking ? . status == ' canceled '
if cancelled
# if the booking is canceelled, lessons are done too. No need to check the focused lesson
return true
else
if @ hasFocusedLesson ( )
return @ focusedLesson ( ) . status == ' canceled '
else
cancelled
2016-04-06 02:23:15 +00:00
isSuspended: () ->
@ state . booking ? . status == ' suspended '
2018-02-15 04:16:32 +00:00
isUnconfirmed: () ->
@ state . booking ? . status == ' unconfirmed '
2016-04-06 02:23:15 +00:00
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: () ->
2016-04-21 14:23:29 +00:00
price = this . state . booking ? . booked_price
if price ?
if typeof price == " string "
price = new Number ( price )
return price . toFixed ( 2 )
else
return price
2016-04-06 02:23:15 +00:00
lessonPaymentAmt: () ->
2016-04-21 14:23:29 +00:00
console . log ( " lessonPaymentAmt " )
2016-04-06 02:23:15 +00:00
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 '
2016-04-21 14:23:29 +00:00
" monthly at $ #{ this . bookedPrice ( ) } per month "
2016-04-06 02:23:15 +00:00
else
" $??? "
selfLastToAct: () ->
if @ isRequested ( )
2016-06-03 04:32:09 +00:00
if @ isCounter ( )
@ counterer ( ) . id == @ myself ( ) . id
else
@ studentViewing ( )
2016-04-06 02:23:15 +00:00
else if @ isCounter ( )
@ counterer ( ) . id == @ myself ( ) . id
else if @ isCanceled ( )
2018-01-27 22:18:04 +00:00
@ canceler ( ) ? . id == @ myself ( ) . id
2016-04-06 02:23:15 +00:00
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) ->
2017-07-10 02:21:29 +00:00
if @ hasFocusedLesson ( ) || slot . slot_type == ' single ' #!@isRecurring(booking)
2016-04-06 02:23:15 +00:00
slot . pretty_start_time
2016-05-30 21:43:55 +00:00
else
" #{ this . dayOfWeek ( slot ) } at #{ this . dayTime ( slot ) } "
2016-04-06 02:23:15 +00:00
slotTimePhrase: (slot) ->
2017-07-10 02:21:29 +00:00
console . log ( " SLOT " , slot )
if slot . slot_type == ' recurring '
# if @isRecurring()
2016-04-06 02:23:15 +00:00
" each " + @ slotTime ( slot )
else
@ slotTime ( slot )
slotMessage: (slot, qualifier = '') ->
@ messageBlock ( slot . mySlot , slot [ qualifier + ' message ' ] )
messageBlock: (selfWroteMessage, message) ->
2018-01-27 22:18:04 +00:00
if typeof selfWroteMessage == ' string '
whoSaid = selfWroteMessage + ' said: '
else if selfWroteMessage
2016-04-06 02:23:15 +00:00
whoSaid = " You said: "
else
whoSaid = " Message from #{ this . other ( ) . first_name } : "
if message && message . length > 0
description = ` < table >
< tbody >
< td className = " description " > { whoSaid } < / td >
< td className = " message " > { message } < / td >
< / tbody >
< / table > `
description
dayTime: (slot) ->
if slot . hour > 11
hour = slot . hour - 12
if hour == 0
hour = 12
am_pm = ' pm '
else
hour = slot . hour
if hour == 0
hour = 12
am_pm = ' am '
2016-05-19 18:26:37 +00:00
" #{ context . JK . padString ( hour . toString ( ) , 2 ) } : #{ context . JK . padString ( slot . minute . toString ( ) , 2 ) } #{ am_pm } ( #{ slot . pretty_timezone } ) "
2016-04-06 02:23:15 +00:00
2016-04-21 14:23:29 +00:00
displayableLesson: () ->
lesson = @ focusedLesson ( )
if ! lesson ?
lesson = @ state . booking . next_lesson
lesson
2016-04-06 02:23:15 +00:00
isStartingSoonOrNow: () ->
# 60 minutes before
2016-04-21 14:23:29 +00:00
startTime = new Date ( @ displayableLesson ( ) . scheduled_start ) . getTime ( )
2016-04-06 02:23:15 +00:00
endTime = ( startTime + @ lessonLength ( ) * 60 )
now = new Date ( ) . getTime ( )
now > startTime && now < endTime
isNow: () ->
2016-04-21 14:23:29 +00:00
startTime = new Date ( @ displayableLesson ( ) . scheduled_start ) . getTime ( )
2016-04-06 02:23:15 +00:00
endTime = ( startTime + @ lessonLength ( ) * 60 )
now = new Date ( ) . getTime ( )
now > startTime && now < endTime
isPast: () ->
2016-04-21 14:23:29 +00:00
new Date ( ) . getTime ( ) > new Date ( @ displayableLesson ( ) . scheduled_start ) . getTime ( )
2016-04-06 02:23:15 +00:00
2016-05-19 18:26:37 +00:00
isMissed: () ->
@ displayableLesson ( ) . missed
2016-04-06 02:23:15 +00:00
sessionLink: () ->
2016-04-21 14:23:29 +00:00
link = " /client # /session/ #{ this . displayableLesson ( ) . music_session_id } "
2016-04-06 02:23:15 +00:00
` < a href = { link } > JOIN SESSION < / a > `
nextLessonSummaryWithAvatar: () ->
` < div className = " row " >
{ this . userHeader ( this . other ( ) ) }
{ this . nextLessonSummary ( ) }
< / div > `
nextLessonSummaryRow: () ->
if @ isActive ( )
if @ isNow ( )
data = ` < p > You should join this session immediately: { this . sessionLink ( ) } < / p > `
else if @ isPast ( )
data = ` < p > This lesson is over . < / p > `
else
2016-04-21 14:23:29 +00:00
data = ` < p > This lesson is scheduled to start at { this . displayableLesson ( ) . pretty_scheduled_start } < / p > `
2016-04-06 02:23:15 +00:00
else if @ isRequested ( )
2016-04-21 14:23:29 +00:00
data = ` < p > This lesson is scheduled to start at { this . displayableLesson ( ) . pretty_scheduled_start } < / p > `
2016-04-06 02:23:15 +00:00
` < div className = " row " >
{ data }
< / div > `
nextLessonSummary: () ->
if @ isActive ( )
if @ isNow ( )
` < p > You should join this session immediately: { this . sessionLink ( ) } < / p > `
else if @ isPast ( )
` < p > This lesson is over . < / p > `
else
2016-04-21 14:23:29 +00:00
` < p > This lesson is scheduled to start at { this . displayableLesson ( ) . pretty_scheduled_start } < / p > `
2016-04-06 02:23:15 +00:00
else if @ isRequested ( )
2016-04-21 14:23:29 +00:00
` < p > This lesson is scheduled to start at { this . displayableLesson ( ) . pretty_scheduled_start } < / p > `
2016-04-06 02:23:15 +00:00
renderCancelLesson: () ->
` < div >
< h3 > Cancel this Lesson < / h3 >
< p > If you would like to cancel this lesson , you have to do so 24 hours in advance . < / p >
< a className = " button-orange cancel-lesson " onClick = { this . onCancelLesson } > CANCEL LESSON < / a >
< / div > `
dayOfWeek: (slot) ->
switch slot . day_of_week
when 0 then " Sunday "
when 1 then " Monday "
when 2 then " Tuesday "
when 3 then " Wednesday "
when 4 then " Thursday "
when 5 then " Friday "
when 6 then " Saturday "
userHeader: (user) ->
photo_url = user ? . photo_url
if ! photo_url ?
photo_url = ' /assets/shared/avatar_generic.png '
2018-01-27 22:18:04 +00:00
if user ?
name = user . name
else
name = ' System '
2016-04-06 02:23:15 +00:00
` < div className = " user-header " >
< div className = " avatar " >
< img src = { photo_url } / >
< / div >
< div className = " user-name " >
2018-01-27 22:18:04 +00:00
{ name }
2016-04-06 02:23:15 +00:00
< / div >
< / div > `
decisionProps: (slots) ->
{
onSlotDecision: this . onSlotDecision ,
2016-04-21 14:23:29 +00:00
onUpdateAllDecision: this . onUpdateAllDecision ,
2016-04-06 02:23:15 +00:00
initial: this . neverAccepted ( ) ,
counter: this . isCounter ( ) ,
is_recurring: this . isRecurring ( ) ,
slot_decision: this . state . slot_decision ,
2016-04-21 14:23:29 +00:00
update_all: this . state . update_all ,
2016-04-06 02:23:15 +00:00
slots: slots ,
otherRole: this . otherRole ( ) ,
onUserDecision: this . onAccept ,
onUserCancel: this . onCancel ,
disabled: this . state . updatingLesson ,
selfLastToAct: this . selfLastToAct ( ) ,
counterErrors: this . state . counterErrors ,
2016-04-21 14:23:29 +00:00
cancelErrors: this . state . cancelErrors ,
2016-06-03 04:32:09 +00:00
focusedLesson: this . focusedLesson ( ) ,
noSlots: this . noSlots ( )
2016-04-06 02:23:15 +00:00
}
render: () ->
if @ state . updating
2016-04-21 14:23:29 +00:00
return @ renderLoading ( )
2016-04-06 02:23:15 +00:00
else if @ teacherViewing ( )
2016-04-21 14:23:29 +00:00
return @ renderTeacher ( )
2016-04-06 02:23:15 +00:00
else if @ studentViewing ( )
2016-04-21 14:23:29 +00:00
return @ renderStudent ( )
2016-04-06 02:23:15 +00:00
else
2016-04-21 14:23:29 +00:00
return @ renderLoading ( )
2016-04-06 02:23:15 +00:00
2016-05-19 18:26:37 +00:00
completedHeader: () ->
if @ isNow ( )
header = ' the lesson is scheduled for right now! '
2016-05-27 01:32:58 +00:00
else
2016-05-19 18:26:37 +00:00
if @ isMissed ( )
header = " this lesson was #{ this . displayableLesson ( ) . displayStatus . toLowerCase ( ) } "
else if @ isSuspended ( )
header = ' this lesson was suspended due to billing issues '
else
header = ' this lesson is over '
approvedHeader: () ->
if @ isCompleted ( )
if @ isMissed ( )
header = " this lesson was #{ this . displayableLesson ( ) . displayStatus . toLowerCase ( ) } "
else if @ isSuspended ( )
header = ' this lesson was suspended due to billing issues '
else
header = ' this lesson is over '
else if @ isNow ( )
header = ' the lesson is scheduled for right now! '
else if @ isPast ( )
header = ' this lesson is over '
else
header = ' this lesson is coming up soon '
header
2016-04-06 02:23:15 +00:00
renderTeacher: () ->
if @ isRequested ( )
header = ' respond to lesson request '
content = @ renderTeacherRequested ( )
2016-05-19 18:26:37 +00:00
else if @ isCounter ( )
2016-04-06 02:23:15 +00:00
if @ isTeacherCountered ( )
header = ' your proposed alternate day/time is still pending '
else
header = ' student has proposed an alternate day/time '
content = @ renderTeacherCountered ( )
2017-07-17 00:38:40 +00:00
else if @ isApproved ( )
header = @ approvedHeader ( )
content = @ renderTeacherApproved ( )
2016-05-19 18:26:37 +00:00
else if @ isCompleted ( )
header = @ completedHeader ( )
content = @ renderTeacherComplete ( )
2016-04-06 02:23:15 +00:00
else if @ isCanceled ( )
2016-05-19 18:26:37 +00:00
header = " this lesson was #{ this . displayableLesson ( ) ? . displayStatus ? . toLowerCase ( ) } "
2016-04-06 02:23:15 +00:00
content = @ renderTeacherCanceled ( )
else if @ isSuspended ( )
header = ' This lesson has been suspended '
content = @ renderTeacherSuspended ( )
2018-02-15 04:16:32 +00:00
else if @ isUnconfirmed ( )
header = ' This lesson has been automatically canceled '
content = @ renderTeacherUnconfirmed ( )
2016-04-21 14:23:29 +00:00
return ` < div className = " content-body-scroller " >
2016-04-06 02:23:15 +00:00
< Nav / >
< h2 > { header } < / h2 >
{ content }
< br className = " clearall " / >
< / div > `
renderStudent: () ->
if @ isRequested ( )
header = ' your lesson has been requested '
content = @ renderStudentRequested ( )
2016-05-19 18:26:37 +00:00
else if @ isCounter ( )
2016-04-06 02:23:15 +00:00
if @ isTeacherCountered ( )
header = ' teacher has proposed an alternate day/time '
else
header = ' your proposed alternate day/time is still pending '
content = @ renderTeacherCountered ( )
2017-07-17 00:38:40 +00:00
else if @ isApproved ( )
header = @ approvedHeader ( )
content = @ renderStudentApproved ( )
2016-05-19 18:26:37 +00:00
else if @ isCompleted ( )
header = @ completedHeader ( )
content = @ renderStudentComplete ( )
2016-04-06 02:23:15 +00:00
else if @ isCanceled ( )
if @ neverAccepted ( ) && @ studentViewing ( ) && ! @ studentCanceled ( )
header = " we ' re sorry, but your lesson request has been declined "
else
2016-05-19 18:26:37 +00:00
header = " this lesson was #{ this . displayableLesson ( ) ? . displayStatus ? . toLowerCase ( ) } "
2016-04-06 02:23:15 +00:00
content = @ renderStudentCanceled ( )
2018-02-15 04:16:32 +00:00
else if @ isUnconfirmed ( )
header = ' this lesson has been automatically canceled '
content = @ renderStudentUnconfirmed ( )
2016-04-06 02:23:15 +00:00
else if @ isSuspended ( )
header = ' this lesson has been suspended '
content = @ renderStudentSuspended ( )
2016-05-23 18:51:58 +00:00
2016-04-06 02:23:15 +00:00
` < div className = " content-body-scroller " >
< Nav / >
< h2 > { header } < / h2 >
{ content }
< br className = " clearall " / >
< / div > `
renderLoading: () ->
2016-04-21 14:23:29 +00:00
header = ' Loading ... '
2016-04-06 02:23:15 +00:00
` < div className = " content-body-scroller " >
< Nav / >
< h2 > { header } < / h2 >
< br className = " clearall " / >
< / div > `
renderStudentRequested: () ->
` < div className = " contents " >
2016-05-30 21:43:55 +00:00
< div className = " row request-sent " >
2016-04-06 02:23:15 +00:00
{ this . userHeader ( this . myself ( ) ) }
Your request has been sent . You will receive an email when { this . teacher ( ) . name } responds .
2016-05-30 21:43:55 +00:00
{ this . createDetail ( ) }
2016-04-06 02:23:15 +00:00
< / div >
2016-05-19 19:45:26 +00:00
< LessonBookingDecision { . . . this . decisionProps ( [ ] ) } / >
2016-04-06 02:23:15 +00:00
< / div > `
2016-05-19 18:26:37 +00:00
joinSessionNow: (e) ->
e . preventDefault ( )
SessionActions . enterSession ( @ displayableLesson ( ) . music_session . id )
updateCreditCard: (e) ->
window . location . href = " /client # /account/paymentHistory "
2016-05-30 21:43:55 +00:00
createDetail: () ->
if @ hasFocusedLesson ( ) || ! @ isRecurring ( )
if @ onlyOption ( ) && @ rescheduling ( )
2016-06-03 04:32:09 +00:00
if @ noSlots ( )
detail = ` < p className = " proposing-new-time no-slot " > You are proposing a date / time for this lesson . < / p > `
else
detail = ` < p className = " proposing-new-time " > You are proposing to change the date / time of the lesson currently scheduled for { this . slotTime ( this . state . booking . default_slot ) } < / p > `
2016-05-30 21:43:55 +00:00
else
2016-06-03 04:32:09 +00:00
if @ noSlots ( )
detail = ` < p className = " generic-time-stmt no-slot " > Your lesson has no scheduled time yet . < / p > `
else
detail = ` < p className = " generic-time-stmt " > Your { this . lessonDesc ( ) } will take place this { this . slotTime ( this . state . booking . default_slot ) } < / p > `
2016-05-30 21:43:55 +00:00
else
if @ onlyOption ( ) && @ rescheduling ( )
detail = ` < p className = " proposing-new-time " > You are proposing to change the date / time of the lesson currently scheduled for { this . slotTime ( this . state . booking . default_slot ) } < / p > `
else
detail = ` < p className = " generic-time-stmt " > Your { this . lessonDesc ( ) } will take place each { this . slotTime ( this . state . booking . default_slot ) } < / p > `
detail
rescheduling: () ->
@ state . purpose == ' rescheduling '
2016-05-19 18:26:37 +00:00
renderStudentComplete: () ->
@ renderStudentApproved ( )
renderTeacherComplete: () ->
@ renderTeacherApproved ( )
2016-04-06 02:23:15 +00:00
renderStudentApproved: () ->
2016-05-19 18:26:37 +00:00
if @ isCompleted ( )
if @ isMissed ( )
whatNow = null
summary = ` < div className = " row " >
{ this . userHeader ( this . displayableLesson ( ) . missedUser ) }
2016-05-27 01:32:58 +00:00
< p > This lesson was missed by { this . displayableLesson ( ) . missedRole } . < / p >
2016-05-19 18:26:37 +00:00
< / div > `
else if @ isSuspended ( )
whatNow = ` < div className = " row " >
< h3 > What Now ? < / h3 >
< p > You should update your credit card info . < a onClick = { this . updateCreditCard } > update credit card < / a > < / p >
< / div > `
else
summary = null
else if @ isNow ( )
2016-04-06 02:23:15 +00:00
2016-05-19 18:26:37 +00:00
if @ studentMadeDefaultSlot ( )
message = this . slotMessage ( this . state . booking . default_slot , ' accept ' )
2016-04-06 02:23:15 +00:00
2016-05-30 21:43:55 +00:00
detail = @ createDetail ( )
2016-05-19 18:26:37 +00:00
summary = ` < div className = " row " >
2016-04-06 02:23:15 +00:00
{ this . userHeader ( this . teacher ( ) ) }
< p > Has accepted your lesson request . < / p >
{ detail }
{ message }
2016-05-19 18:26:37 +00:00
< / div > `
whatNow = ` < div className = " row " >
2016-04-06 02:23:15 +00:00
< h3 > What Now ? < / h3 >
2016-05-19 18:26:37 +00:00
< p > You should join the lesson session as soon as possible . < a onClick = { this . joinSessionNow } > join session now < / a > < / p >
{ this . nextLessonSummary ( ) }
< / div > `
else if @ isPast ( )
if @ studentMadeDefaultSlot ( )
message = this . slotMessage ( this . state . booking . default_slot , ' accept ' )
2016-05-30 21:43:55 +00:00
detail = @ createDetail ( )
2016-05-19 18:26:37 +00:00
summary = ` < div className = " row " >
{ this . userHeader ( this . teacher ( ) ) }
< p > Has accepted your lesson request . < / p >
{ detail }
{ message }
< / div > `
else
2016-05-23 18:51:58 +00:00
if @ studentMadeDefaultSlot ( )
message = this . slotMessage ( this . state . booking . default_slot , ' accept ' )
2016-05-30 21:43:55 +00:00
detail = @ createDetail ( )
2016-05-23 18:51:58 +00:00
summary = ` < div className = " row " >
{ this . userHeader ( this . teacher ( ) ) }
< p > Has accepted your lesson request . < / p >
{ detail }
{ message }
< / div > `
2016-05-19 18:26:37 +00:00
decision = ` < LessonBookingDecision { . . . this . decisionProps ( [ ] ) } / > `
` < div className = " contents " >
{ summary }
{ whatNow }
{ decision }
2016-04-06 02:23:15 +00:00
< / div > `
2016-05-19 18:26:37 +00:00
2016-04-06 02:23:15 +00:00
renderStudentCanceled: () ->
@ renderCanceled ( )
renderStudentSuspended: () ->
# <p className="description">Message from {this.other().first_name}:</p>
# <div className="message"></div>
2018-02-15 04:16:32 +00:00
renderStudentUnconfirmed: () ->
@ renderUnconfirmed ( )
2016-04-06 02:23:15 +00:00
renderStudentCountered: () ->
@ renderCountered ( )
renderTeacherRequested: () ->
if @ isTestDrive ( )
action = ` < p className = " action " > Has requested a TestDrive { this . lessonLength ( ) } - minute lesson , for which you will be paid $10 . < / p > `
else
action = ` < p className = " action " > Has requested a { this . lessonDesc ( ) } lesson , for which you will be paid { this . lessonPaymentAmt ( ) } . < / p > `
2016-06-03 04:32:09 +00:00
if @ noSlots ( )
slots = [ ]
else
slots = [ this . state . booking . default_slot ]
if this . state . booking . alt_slot ?
slots . push ( this . state . booking . alt_slot )
2016-04-06 02:23:15 +00:00
` < div className = " contents " >
< div className = " row " >
{ this . userHeader ( this . other ( ) ) }
{ action }
{ this . slotMessage ( this . state . booking . default_slot ) }
< / div >
2016-06-03 04:32:09 +00:00
< LessonBookingDecision { . . . this . decisionProps ( slots ) } / >
2016-04-06 02:23:15 +00:00
< / div > `
renderTeacherApproved: () ->
2016-05-19 18:26:37 +00:00
if @ isCompleted ( )
if @ isMissed ( )
whatNow = null
summary = ` < div className = " row " >
{ this . userHeader ( this . displayableLesson ( ) . missedUser ) }
2016-05-27 01:32:58 +00:00
< p > This lesson was missed by { this . displayableLesson ( ) . missedRole } . < / p >
2016-05-19 18:26:37 +00:00
< / div > `
else if @ isSuspended ( )
whatNow = ` < div className = " row " >
< h3 > What Now ? < / h3 >
< p > You should update your credit card info . < a onClick = { this . updateCreditCard } > update credit card < / a > < / p >
< / div > `
else
summary = null
else if @ isNow ( )
if @ studentMadeDefaultSlot ( )
message = this . slotMessage ( this . state . booking . default_slot , ' accept ' )
2016-05-30 21:43:55 +00:00
detail = @ createDetail ( )
2016-05-19 18:26:37 +00:00
summary = ` < div className = " row " >
{ this . userHeader ( this . student ( ) ) }
< p > Is ready to take the lesson . < / p >
{ detail }
{ message }
< / div > `
whatNow = ` < div className = " row " >
< h3 > What Now ? < / h3 >
< p > You should join the lesson session as soon as possible . < a onClick = { this . joinSessionNow } > join session now < / a > < / p >
{ this . nextLessonSummary ( ) }
< / div > `
else if @ isPast ( )
else
2016-05-26 21:25:51 +00:00
if @ studentMadeDefaultSlot ( )
message = this . slotMessage ( this . state . booking . default_slot , ' accept ' )
2016-05-30 21:43:55 +00:00
detail = @ createDetail ( )
2016-05-26 21:25:51 +00:00
summary = ` < div className = " row " >
{ this . userHeader ( this . teacher ( ) ) }
< p > Has accepted your lesson request . < / p >
{ detail }
{ message }
< / div > `
2016-05-19 18:26:37 +00:00
decision = ` < LessonBookingDecision { . . . this . decisionProps ( [ ] ) } / > `
2016-04-06 02:23:15 +00:00
` < div className = " contents " >
2016-05-19 18:26:37 +00:00
{ summary }
{ whatNow }
{ decision }
2016-04-06 02:23:15 +00:00
< / div > `
2016-05-19 18:26:37 +00:00
2016-04-06 02:23:15 +00:00
renderTeacherCanceled: () ->
@ renderCanceled ( )
renderTeacherSuspended: () ->
2018-02-15 04:16:32 +00:00
renderTeacherUnconfirmed: () ->
@ renderUnconfirmed ( )
2016-04-06 02:23:15 +00:00
renderTeacherCountered: () ->
@ renderCountered ( )
2018-02-15 04:16:32 +00:00
renderUnconfirmed: () ->
action = ` < p > The JamKazam system has canceled this request because it was never acknowledged after too long of a time . < / p > `
2016-04-06 02:23:15 +00:00
renderCanceled: () ->
canceler = @ canceler ( )
myself = @ myself ( )
initial = @ neverAccepted ( )
if initial
2018-01-27 22:18:04 +00:00
if @ adminCanceled ( )
action = ` < p > A JamKazam administrator canceled this lesson request . < / p > `
else if @ studentViewing ( )
2016-04-06 02:23:15 +00:00
if @ studentCanceled ( )
action = ` < p > You canceled this lesson request . < / p > `
else
action = ` < p > Has declined your lesson request . < / p > `
else
if @ studentCanceled ( )
action = ` < p > Has canceled this lesson request . < / p > `
else
action = ` < p > You declined this lesson request . < / p > `
2018-02-15 04:16:32 +00:00
2016-04-06 02:23:15 +00:00
if @ studentViewing ( )
2018-01-27 22:18:04 +00:00
if @ adminCanceled ( ) || @ studentCanceled ( )
2016-04-06 02:23:15 +00:00
blurb = ` < p > 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</p>`
else
blurb = ` < p > 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</p>`
whatNow =
` < div className = " row " >
< h3 > What Now ? < / h3 >
{ blurb }
< a href = " /client # /jamclass/searchOptions " className = " search-for-more-teachers " > SEARCH INSTRUCTORS NOW < / a >
< / div > `
2018-01-27 22:18:04 +00:00
cancelerUser = null
if this . adminCanceled ( )
cancelerUser = ' System '
else
cancelerUser = this . selfCanceled ( )
2016-04-06 02:23:15 +00:00
` < div className = " contents " >
< div className = " row " >
{ this . userHeader ( canceler ) }
{ action }
2018-01-27 22:18:04 +00:00
{ this . messageBlock ( cancelerUser , this . state . booking . cancel_message ) }
2016-04-06 02:23:15 +00:00
< / div >
{ whatNow }
< / div > `
renderCountered: () ->
counterer = @ counterer ( )
myself = @ myself ( )
phrase = this . slotTimePhrase ( this . counteredSlot ( ) )
action = ` < p > Has suggested a different time for your lesson . < / p > `
2016-06-03 13:41:14 +00:00
detail = ` < p className = " counter-stmt " > Proposed alternate day / time is { phrase } < / p > `
2016-04-06 02:23:15 +00:00
` < div className = " contents " >
< div className = " row " >
{ this . userHeader ( counterer ) }
{ action }
{ detail }
{ this . slotMessage ( this . counteredSlot ( ) ) }
< / div >
2017-07-17 00:38:40 +00:00
< LessonBookingDecision { . . . this . decisionProps ( [ this . counteredSlot ( ) ] ) } / >
2016-04-06 02:23:15 +00:00
< / div > `
} )