Our favorite live events such as shows, interviews, and concerts have dwindled during the pandemic. Hack (a social rendition of Slack, the workplace messaging app) is now making connections with your favorite social figures possible. With Hack, you can chat with any social icons about their art and content. Log in now to the Dinner Party workspace to meet your favorites!
Submitting a message will invoke the speak function with relevant message params in the channel subscription method.
class MessageForm extends React.Component {
handleSubmit(e) {
e.preventDefault();
App.cable.subscriptions.subscriptions[0].speak({ message: this.state.body, id: this.props.currentUser, channelId: this.props.channelId});
this.setState({ body: "" });
}
}
When the speak function is invoked from message submission, the speak function on the backend in the ChatChannel (which derives from Ruby's Application Cables) is invoked with relevant params.
class ChatRoom extends React.Component{
subscribeToChannel() {
App.cable.subscriptions.create(
{ channel: "ChatChannel",
id: this.props.currentView
},
{
received: data => {
switch(data.type){
case ("createMessage"):
const message = {
id: data.id,
body: data.message,
authorId: data.author_id,
channelId: data.channel_id,
createdAt: data.created_at
}
this.props.createMessage(message)
this.setState({
messages: this.props.messages
});
case ("deleteMessage"):
this.props.deleteMessage(data.message)
this.setState({
messages: this.props.messages
});
}
},
speak: function(data) {return this.perform("speak", data)},
update: function(data) {return this.perform("update", data)},
delete: function(data) {return this.perform("delete", data)},
reply: function(data) {return this.perform("reply", data)}
}
)
}
When the speak function successfully saves a message, it broadcasts data to a socket within the subscribed stream. Data is received and subsequently maniupulated in the subscription method above.
class ChatChannel < ApplicationCable::Channel
def subscribed
# dynamically subscribing to a channel
@channel = Channel.find(params[:id])
stream_for @channel
end
def speak(data)
#saving a message with params and broadcasting to a socket
message = Message.new(body: data['message'], author_id: data['id'], channel_id: data['channelId'])
if message.save
socket = { message: message.body, type: 'createMessage', id: message.id, author_id: message.author_id, channel_id: message.channel_id, created_at: message.created_at}
ChatChannel.broadcast_to(@channel, socket)
end
end
def reply(data)
message = Message.new(body: data['message'], author_id: data['id'], channel_id: data['channelId'], parent_message_id: data['parentMessageId'])
if message.save
socket = { message: message.body, type: 'replyMessage', id: message.id, author_id: message.author_id, channel_id: message.channel_id, created_at: message.created_at, parent_message_id: message.parent_message_id}
ChatChannel.broadcast_to(@channel, socket)
end
end
class ChatRoom extends React.Component{
{this.state.replying || this.state.threadMessages.length > 0 ?
<div className="thread">
<Thread users={this.props.users} currentUser={this.props.currentUser} channels={this.props.channels} channelId={this.props.currentView} threadMessages={this.state.threadMessages} message={this.replyMessage} messages={this.props.messages}/>
{this.state.threadMessages = []}
{this.state.replying = false}
</div> : ""
}
}
class Thread extends React.Component {
render() {
const messageList = this.state.messages.length > 0 ? this.state.messages.reverse().map((message, idx) => {
let timeStampArray = new Date(`${message.createdAt}`).toLocaleString().split(" ")
let timestamp = timeStampArray[1].slice(0,timeStampArray[1].length - 3) + " " + timeStampArray[2].toLowerCase()
return (
<li className="message-box" key={message.id}>
<div className="message-author">{this.props.users[message.authorId].displayName}
<p className="message-time">{timestamp}</p>
</div>
<p className="message-content">{message.body}</p>
</li>)
}) : ""
return (
<div ref={this.closeThread} className="thread-container">
<div className="thread-name">{`Thread #${this.props.channels[this.props.channelId].name.toLowerCase()}`}</div>
<div className="message-list" >{messageList}</div>
<ReplyMessageForm currentUser={this.props.currentUser} parentMessageId={this.props.message.id} channelId={this.props.channelId}/>
<button className="close-thread" onClick={this.modalDisappears.bind(this)}>X</button>
</div>
)
}
}
}