Created
April 26, 2017 16:26
-
-
Save dphase/79102ba81b5e79fc6fae168a6416b2e1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import _ from 'lodash' | |
import alt from '../alt' | |
import MessageActions from '../actions/Messages' | |
import SocketActions from '../actions/Socket' | |
class MessageStore { | |
constructor() { | |
this.messages = [] | |
this.bindListeners({ | |
handleUpdateMessages: [ MessageActions.UPDATE_MESSAGES, SocketActions.UPDATE_MESSAGES ], | |
handleFetchMessages: [ MessageActions.FETCH_MESSAGES ] | |
}) | |
} | |
handleUpdateMessages(message) { | |
// only save the message to the store if it hasn't been previously saved | |
// ---------------------------------------------------------------------------- | |
if (!_.find(this.messages, m => m.id === message.id)) { | |
this.messages.push(message) | |
} | |
} | |
handleFetchMessages() { | |
this.messages = [] | |
} | |
} | |
export default alt.createStore(MessageStore, 'MessageStore') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import ReactDOM from 'react-dom' | |
import Block from 'react-blocks' | |
import moment from 'moment' | |
import request from 'superagent' | |
import _ from 'lodash' | |
import config from 'config' | |
import SocketStore from '../stores/SocketStore' | |
import SocketActions from '../actions/Socket' | |
import MessageStore from '../stores/MessageStore' | |
import MessageActions from '../actions/Messages' | |
import MessageBubble from './MessageBubble' | |
import MessageInput from './MessageInput' | |
import ContactFinder from './ContactLookup' | |
import Styles from '../styles/Styles' | |
class MessageView extends React.Component { | |
constructor(props) { | |
super(props) | |
this.state = MessageStore.getState() | |
this.state.conversation = null | |
} | |
// Component lifecycle | |
// ------------------------------------------------------------------------------ | |
componentDidMount() { | |
MessageStore.listen(::this.onChange) | |
SocketActions.fetchMessages() | |
if (this.props.params.conversation) { | |
MessageActions.fetchMessages(this.props.params.conversation) | |
this.findConversationAJAX() | |
} | |
} | |
componentWillUnmount() { | |
this.ignoreLastFetch = true | |
MessageStore.unlisten(::this.onChange) | |
} | |
// FIXME: this is awful and bad | |
// ------------------------------------------------------------------------------ | |
componentWillReceiveProps(nextProps) { | |
let oldID = this.props.params.conversation | |
let newID = nextProps.params.conversation | |
if (newID && (newID !== oldID)) { | |
this.findConversationAJAX() | |
} | |
} | |
componentDidUpdate(prevProps, prevState) { | |
let oldID = prevProps.params.conversation | |
let newID = this.props.params.conversation | |
if (newID && (newID !== oldID)) { | |
MessageActions.fetchMessages(this.props.params.conversation) | |
} | |
} | |
onChange(state) { | |
this.setState(state) | |
} | |
// Find contact_id for conversation | |
// ------------------------------------------------------------------------------ | |
findConversationAJAX() { | |
return request | |
.get(`${config.apiServer}/commo/conversations`) | |
.set('x-ss-api-key', config.apiKey) | |
.set('x-ss-token', config.userToken) | |
.end((err, res) => { | |
let contact = (_.find( | |
JSON.parse(res.text), | |
m => m.id === this.props.params.conversation | |
)) | |
this.setState({messages: this.state.messages, conversation: contact}) | |
}) | |
} | |
// Sorted messages | |
// ------------------------------------------------------------------------------ | |
sortedMessages() { | |
return _.sortBy(this.state.messages, m => m.created_at) | |
} | |
// UI rendering | |
// ------------------------------------------------------------------------------ | |
renderMessage(message) { | |
if (message.conversation_id === this.props.params.conversation) { | |
return ( | |
<MessageBubble | |
key = {message.id} | |
data = {message} | |
/> | |
) | |
} | |
} | |
render() { | |
let { sms, foreman } = Styles | |
let inputBox = <br /> | |
let contactBox = <ContactFinder {...this.props} /> | |
let messageContainer | |
if (this.props.params.conversation) { | |
if (this.state.conversation) { | |
inputBox = <MessageInput {...this.props} contact={this.state.conversation.contact} /> | |
contactBox = <ContactFinder | |
{...this.props} | |
contact={this.state.conversation.contact} | |
/> | |
messageContainer = <MessageItemsContainer | |
conversation = {this.props.params.conversation} | |
messages = {this.sortedMessages()} | |
/> | |
} | |
} else { | |
messageContainer = <div style={sms.helpBox}>Choose a conversation from your inbox on the left or use Student Search<br/>to create a new conversation with a student's contact</div> | |
} | |
return ( | |
<Block style={sms.messageViewContainer} layout vertical flex> | |
<Block> | |
{contactBox} | |
</Block> | |
{messageContainer} | |
<Block end> | |
{inputBox} | |
</Block> | |
</Block> | |
) | |
} | |
} | |
class MessageItemsContainer extends React.Component { | |
constructor(props) { | |
super(props) | |
} | |
// Lifecyle events to manage funky scrolling | |
// ------------------------------------------------------------------------------ | |
componentDidMount() { | |
// FIXME: possibly add scrollPosition to state | |
this.scrollPosition = 0 | |
this.domNode().addEventListener('scroll', ::this.handleScroll) | |
} | |
componentWillUpdate() { | |
let node = this.domNode() | |
this.shouldScrollDown = this.scrollPosition + node.clientHeight === node.scrollHeight | |
} | |
componentDidUpdate() { | |
let node = this.domNode() | |
node.scrollTop = this.shouldScrollDown ? node.scrollHeight : this.scrollPosition | |
this.scrollPosition = node.scrollTop | |
} | |
// DOM helpers for scrolling | |
// ------------------------------------------------------------------------------ | |
domNode() { | |
return ReactDOM.findDOMNode(this) | |
} | |
handleScroll() { | |
this.scrollPosition = this.domNode().scrollTop | |
} | |
// Rendering | |
// ------------------------------------------------------------------------------ | |
renderMessage(message) { | |
if (message.conversation_id === this.props.conversation) { | |
return ( | |
<MessageBubble | |
key = {message.id} | |
data = {message} | |
/> | |
) | |
} | |
} | |
render() { | |
let { sms, foreman } = Styles | |
return ( | |
<Block style={sms.bubbleContainer} flex> | |
{this.props.messages.map((m) => { | |
return ::this.renderMessage(m) | |
})} | |
</Block> | |
) | |
} | |
} | |
export default MessageView |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import alt from '../alt' | |
import Faye from 'faye/browser/faye-browser' | |
import config from 'config' | |
class SocketActions { | |
constructor() { | |
let faye_url = `${config.apiServer}/rt` | |
this.faye = new Faye.Client(faye_url, { | |
timeout: 120 | |
}) | |
} | |
updateMessages(messages) { | |
return messages | |
} | |
fetchMessages() { | |
this.faye.subscribe(`/user/${config.userID}`, (msg) => { | |
this.updateMessages(msg) | |
}) | |
} | |
} | |
export default alt.createActions(SocketActions) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import alt from '../alt' | |
import Actions from '../actions/Socket' | |
class SocketStore { | |
constructor() { | |
this.messages = [] | |
this.bindListeners({ | |
handleUpdateMessages: Actions.UPDATE_MESSAGES, | |
handlleFetchMessages: Actions.FETCH_MESSAGES | |
}) | |
} | |
handleUpdateMessages(message) { | |
this.messages.push(message) | |
} | |
handlleFetchMessages() { | |
this.messages = [] | |
} | |
} | |
export default alt.createStore(SocketStore, 'SocketStore') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment