/Slick

Slack clone-- "Searchable Log of Infinite Conversation and Knowledge"

Primary LanguageRubyMIT LicenseMIT

Welcome to Slick!

Slick is a collaboration hub that fosters constructive communication and improves workflow for your team.

Live Demo

Features

  • CRUD functionalities for Workspaces, Channels, Direct Messages, and Messages. Users will communicate more effectively by targeting the right audience.
  • Live message updates to help you stay up to speed.
  • Search-enabled direct message creation to help you find the users in your workspace faster.

Technologies

Slick is a single-page slack clone utilizing PostgreSQL, Ruby on Rails, and React.

Other technologies used:

  • Action Cable (Websockets) was utilized to implement the messaging service.
  • jQuery allowed for API calls for communication between frontend and backend.

Screenshots

Create Workspace Messages

Technical Info

Chat Message Rendering

Chat messages are handled and rendered in different ways depending on their context, which includes who the sender is, whether the message is part of a group of messages, the date of messages, and whether the message is being edited:

render() {
        const chatIndexDisplay = [];
        let timeBucketContent;
        let lastTimestamp = null;
        let lastSenderId = null;

        this.props.messages.forEach((message) => {
            let messageTimestamp = new Date(message.createdAt)
            if (!lastTimestamp || messageTimestamp.toDateString() !== lastTimestamp.toDateString()) {
                if (lastTimestamp) {
                    chatIndexDisplay.push(<TimeBucket key={lastTimestamp.toDateString()} messageTimestamp={lastTimestamp}>
                        {timeBucketContent}
                    </TimeBucket>)
                }
                timeBucketContent = []
            }
            if (this.state.messageUnderEdit === message.id) {
                timeBucketContent.push(<ChatItemEditForm message={message} updateMessage={(body)=>this.props.updateMessage(message.id, body)} clearMessageUnderEdit={this.clearMessageUnderEdit}/>)
            }
            else if (message.senderId !== lastSenderId) {
                timeBucketContent.push(<ChatItemContainer placeMessageUnderEdit={this.placeMessageUnderEdit} deleteMessage={() => this.props.deleteMessage(message.id)} key={message.id} hasMessageHeader={true} message={message} />)
            } else if (!lastTimestamp || (messageTimestamp - lastTimestamp) > 1800000) {
                timeBucketContent.push(<ChatItemContainer placeMessageUnderEdit={this.placeMessageUnderEdit} deleteMessage={() => this.props.deleteMessage(message.id)} key={message.id} hasMessageHeader={true} message={message} />)
            } else {
                timeBucketContent.push(<ChatItemContainer placeMessageUnderEdit={this.placeMessageUnderEdit} deleteMessage={() => this.props.deleteMessage(message.id)} key={message.id} hasMessageHeader={false} message={message} />)
            }
            lastTimestamp = messageTimestamp;
            lastSenderId = message.senderId;
        })
        if (lastTimestamp) {
            chatIndexDisplay.push(<TimeBucket key={lastTimestamp.toDateString()} messageTimestamp={lastTimestamp}>
                {timeBucketContent}
            </TimeBucket>)
        }


        return (
            <div className="workspace-main-chat-list">
                {chatIndexDisplay}
            </div>
        )
    }

Future Features

  • Message Search
  • Message Notifications