Slick, a clone of the popular messaging app Slack, allows users from a workspace to live chat with each other through direct messages or through channels, and organizes these conversations.
- JavaScript
- React
- Redux
- Ruby On Rails
- PostgreSQL
- ActionCable (for WebSockets)
- HTML5
- SCSS
Slick's core application is built around the WebSocket Communication Protocol to provide to users live updates without refreshing the page. The back end is built using Ruby on Rails and the database using PostgreSQL. The front end is built using React.js, Redux for the global state management of the application, HTML5, and SCSS.
- Logged in users that are subscribed to a specific room will receive live updates of the changes that occur in it without having to refresh the page
- Users can also see in real time if a channel was edited or deleted, and if a new direct message conversation directed to them by another user was created
slick-new-show.mp4
- Users can create an account and login/logout with their credentials.
- Users can choose to login with a Demo User account, which will provide them with access to all of the application’s features.
- Users cannot use the application without first logging in.
- User authentication uses Rails’ session object to store in the database a session token to authenticate users after logging in.
- Users can communicate with other users in real time through messages
- Users can create messages
- Users can edit their messages
- Users can delete their messages
- Users can send emojis in their messages, thanks to the React Emoji Picker package
- Users get notifications of unseen messages in chat sidebar
- Users can create workspaces
- Users can choose which workspace to work on
- Users can invite other users to their workspaces and join other workspaces
- Users can switch between the workspaces that they're members of
- Only the owner of the workspace can create channels to have group conversations with other users from same workspace
- Users can edit their owned channels
- Users can delete their owned channels
- Users can create one-to-one or group direct message conversations with selected members from same workspace and chat with them
- When creating a new message, users can search to which user, channel, or existing conversation they want to send it
- Users can search for users that are not members of the workspace they're currently signed in, and add them to it
- When a message is created, the
RECEIVE_MESSAGE
action gets triggered and any user currently subscribed to that slice of state will receive updates of it whenever it changes. This logic makes sure that when a message gets created in a specific room (channel or direct message conversation) of a workspace, only users that have that conversation open get their 'messages' slice of state updated.
// frontend/src/store/messages.js line 87
export default function messageReducer(state = {}, action) {
switch (action.type) {
....
case RECEIVE_MESSAGE:
let checker = state[Object.keys(state)[0]];
if (checker) {
if (
checker.messageableId === action.message.messageableId &&
checker.messageableType === action.message.messageableType
) {
return { ...state, [action.message.id]: action.message };
}
} else {
return state;
}
break;
...
}
}
- This logic deals with the addition of new members of a workspace. The update controller action of the
workspaces_controller.rb
can receive new users through the request params. After checking that those users don't already belong to that workspace, subscriptions are created so that the new users become members of the workspace, and of the channels that that workspace has. Because the param that contains the new users comes as JSON, the method makes use ofActiveSupport::JSON.decode()
to turn it into Ruby syntax.
# app/api/workspaces_controller.rb line 31
def update
@workspace = Workspace.find_by_id(params[:id])
@users = ActiveSupport::JSON.decode(params[:new_users])
if @users.length > 0
@user_ids = @users.map {|user| user["id"]}
@channels = @workspace.channels
@user_ids.each do |id|
WorkspaceSubscription.create(user_id: id, workspace_id: @workspace.id)
@channels.each do |channel|
ChannelSubscription.create(user_id: id, channel_id: channel.id)
end
end
end
if @workspace.update(workspace_params)
WorkspacesChannel.broadcast_to @workspace,
type: 'EDIT_WORKSPACE',
**from_template('api/workspaces/show', workspace: @workspace)
render json: nil, status: :ok
else
render json: {errors: @workspace.errors.full_messages}, status: 422
end
end
- User profiles and profile image upload
- Remove users from workspace