context = window rest = new context.JK.Rest() ChatActions = @ChatActions SessionStore = @SessionStore @ChatWindow = React.createClass({ mixins: [Reflux.listenTo(@AppStore, "onAppInit"), Reflux.listenTo(@UserStore, "onUserChanged"), Reflux.listenTo(@ChatStore, "onChatChanged")] lastChannel: null getInitialState: () -> state = context.ChatStore.getState() state getInitialProps: () -> {newFormat:true} onChatChanged: (chatState) -> @setState(chatState) onUserChanged: (userState) -> @setState(userState) onAppInit: (app) -> @app = app activateChannel: (channel, e) -> e.preventDefault() ChatActions.activateChannel(channel); convertPurpose: (purpose) -> if !purpose? return '' switch purpose when 'Lesson Requested' then 'requested lesson' when 'Lesson Canceled' then 'canceled lesson' when 'Lesson Approved' then 'approved lesson' when 'All Lesson Times Updated' then 'updated all lesson times' when 'Lesson Updated Time Approved' then 'updated lesson time' when 'New Time Proposed' then 'proposed new time' when 'Lesson Declined' then 'declined lesson' when 'Notation File' then 'attached a notation file' when 'Audio File' then 'attached an audio file' when 'JamKazam Recording' then 'attached a recording' when 'Lesson Timeout' then 'canceled by system' when 'Video Uploaded' then 'uploaded video' else purpose notationClicked: (music_notation, e) -> e.preventDefault() rest.getMusicNotation(music_notation.id).done((response) => context.JK.popExternalLink(response.url) ) .fail((jqXHR) => context.JK.Banner.showAlert('Unable to fetch URL for music notation. Error: ' + jqXHR.responseText) ) audioClicked: (music_notation, e) -> e.preventDefault() rest.getMusicNotation(music_notation.id).done((response) => context.JK.popExternalLink(response.url) ) .fail((jqXHR) => context.JK.Banner.showAlert('Unable to fetch URL for audio. Error: ' + jqXHR.responseText) ) recordingClicked: (recording, e) -> e.preventDefault() context.JK.popExternalLink("/recordings/#{recording.id}") videoClicked: (recording, e) -> e.preventDefault() context.JK.popExternalLink("https://www.youtube.com/watch?v=#{recording.video_id}") openMenu: (lesson, e) -> $this = $(e.target) if !$this.is('.lesson-session-actions-btn') $this = $this.closest('.lesson-session-actions-btn') $this.btOn() render: () -> if @state.channel == 'lesson' chatTabs = `
attach file
` else if !this.props.hideHeader tabs = [] for channel of @state.msgs classes = {} classes[channel] = true classes['chat-tab'] = true classes['active'] = channel == @state.channel if channel == 'global' display = 'Global' else if channel == 'session' display = 'Session' else if channel == 'lesson' display = 'Lesson' else if !channel? display = 'Global' else display = 'Unknown' if display == 'Unknown' continue tabs.push(`
{display}
`) chatTabs = `
{tabs}
` msgs = [] openBig = null if @activeChannelType() == 'lesson' activeChannel = @state.lessonSessionId else activeChannel = @state.channel if activeChannel == 'global' openBig = `Expand` activeMsgs = @state.msgs[activeChannel] || [] for msg in activeMsgs timeago = $.timeago(msg.created_at) if msg.sender_id == context.JK.currentUserId sender = "me" else sender = msg.sender_name if msg.purpose purpose = `
{this.convertPurpose(msg.purpose)}
` else purpose = null additional = null if msg.purpose == 'Notation File' additional = `{msg.music_notation.file_name}` else if msg.purpose == 'Audio File' additional = `{msg.music_notation.file_name}` else if msg.purpose == 'JamKazam Recording' additional = `{msg.claimed_recording.name}` else if msg.purpose == 'Video Uploaded' additional = `Watch on YouTube` msgs.push(`
{sender}{purpose} {msg.msg} {additional}
`) if this.props?.showEmailNotice otherName = this.props?.other?.name emailSentNotice = `
an email will be sent if {otherName} is offline
` if this.props?.showClose closeBtn = `CLOSE` topClasses = {ChatWindow: true} if this.props?.rootClass? topClasses[this.props.rootClass] = true if this.props.rootClass == 'ChatDialog' attachFiles = `attach file
` `
{openBig} {chatTabs}
{msgs}
SEND {closeBtn} {emailSentNotice} {attachFiles}
` openChatDialog: () -> @app.layout.showDialog('chat-dialog', {d1: 'global'}) activeChannelType: () -> @state.channelType sendMessage:()-> if !context.JK.JamServer.connected return false msg = @textBox.val() if !msg? || msg == '' # don't bother the server with empty messages return false; if !@sendingMessage @sendingMessage = true target_user_id = this.props?.other?.id ChatActions.sendMsg(msg, @sendMsgDone, @sendMsgFail, target_user_id, @activeChannelType()) sendMsgDone: () -> @textBox.val('') @sendingMessage = false sendMsgFail: (jqXHR) -> if jqXHR.status == 404 @app.notifyServerError(jqXHR, 'Session chat is only available while in session.') else @app.notifyServerError(jqXHR, 'Unable to Send Chat Message') @sendingMessage = false handleSendMessage: (e) -> e.preventDefault() @sendMessage() handleCloseMessage: (e) -> e.preventDefault() this.props.onCloseClicked() componentDidMount: () -> @root = $(@getDOMNode()) @textBox = @root.find('textarea') componentDidUpdate: () -> if @lastChannel != @state.channel speed = 0 else speed = 'slow' @lastChannel = @state.channel #speed = 0 #slow $scroller = @root.find('.chat-list-scroller') $scroller.animate({scrollTop: $scroller[0].scrollHeight}, speed) items = @root.find('.chat-tabs .lesson-session-actions-btn') @hookupMenu(items) items = @root.find('#attach-files-chat-dialog') @hookupMenu(items) hookupMenu: (items) -> $.each(items, (i, node) => ( $node = $(node) chat_dialog = this.props.rootClass == 'ChatDialog' lesson = {id: $node.attr('data-lesson-id'), attachments_only: true, chat_dialog: chat_dialog} $node.lessonSessionActions(lesson).off(context.JK.EVENTS.LESSON_SESSION_ACTION).on(context.JK.EVENTS.LESSON_SESSION_ACTION, @lessonSessionActionSelected) )) lessonSessionActionSelected: (e, data) -> lessonId = data.options.id if data.lessonAction == 'attach-recording' window.AttachmentActions.startAttachRecording.trigger(lessonId, SessionStore.id()) else if data.lessonAction == 'attach-notation' window.AttachmentActions.startAttachNotation.trigger(lessonId, SessionStore.id()) else if data.lessonAction == 'attach-audio' window.AttachmentActions.startAttachAudio.trigger(lessonId, SessionStore.id()) pasteIntoInput: (el, text) -> el.focus(); if typeof el.selectionStart == "number" && typeof el.selectionEnd == "number" val = el.value selStart = el.selectionStart el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd) el.selectionEnd = el.selectionStart = selStart + text.length else if typeof document.selection != "undefined" textRange = document.selection.createRange() textRange.text = text textRange.collapse(false) textRange.select() handleEnter: (evt) -> if evt.keyCode == 13 && evt.shiftKey evt.preventDefault() @pasteIntoInput($(evt.target).get(0), "\n") else if evt.keyCode == 13 && !evt.shiftKey @sendMessage() })