Add chat channel indicator (#379)
* Add new message indicator to chat * Add indicator switch to chat * Add chat switch indicator
This commit is contained in:
parent
4171a0814a
commit
10c3b52b0a
9 changed files with 96 additions and 8 deletions
|
|
@ -121,6 +121,21 @@
|
|||
box-shadow: 3px 3px 0px $dark-purple;
|
||||
}
|
||||
|
||||
.chatchanneltabindicator{
|
||||
display: inline-block;
|
||||
background: white;
|
||||
border: 2px solid $light-medium-gray;
|
||||
padding: 5px;
|
||||
border-radius: 100px;
|
||||
vertical-align: -2px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.chatchanneltabindicator--new{
|
||||
background: $yellow;
|
||||
border: 2px solid $black;
|
||||
}
|
||||
|
||||
@keyframes example {
|
||||
// animation-name: example;
|
||||
// animation-duration: 4s;
|
||||
|
|
@ -157,11 +172,11 @@
|
|||
}
|
||||
|
||||
.chatmessagebody__profileimage {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin-right: 3px;
|
||||
height: 23px;
|
||||
width: 23px;
|
||||
margin-right: 6px;
|
||||
border-radius: 20px;
|
||||
vertical-align: bottom;
|
||||
vertical-align: -5px;
|
||||
}
|
||||
|
||||
.chatmessagebody__username {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,13 @@ class ChatChannelsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def open
|
||||
@chat_channel = ChatChannel.find(params[:id])
|
||||
raise unless @chat_channel.has_member?(current_user)
|
||||
@chat_channel.chat_channel_memberships.where(user_id: current_user.id).first.touch(:last_opened_at)
|
||||
render json: { status: "success", channel: params[:id] }, status: 200
|
||||
end
|
||||
|
||||
def moderate
|
||||
@chat_channel = ChatChannel.find(params[:id])
|
||||
authorize @chat_channel
|
||||
|
|
|
|||
|
|
@ -43,7 +43,12 @@ class PagesController < ApplicationController
|
|||
end
|
||||
|
||||
def chat
|
||||
@chat_channels = current_user.chat_channels.order("last_message_at DESC")
|
||||
@chat_channels = current_user.chat_channels.
|
||||
order("last_message_at DESC").
|
||||
includes(:chat_channel_memberships)
|
||||
@chat_channels.each do |channel|
|
||||
channel.current_user = current_user
|
||||
end
|
||||
slug = if params[:slug] && params[:slug].start_with?("@")
|
||||
[current_user.username, params[:slug].gsub("@", "")].sort.join("/")
|
||||
else
|
||||
|
|
|
|||
|
|
@ -30,6 +30,22 @@ export function sendMessage(activeChannelId, message, successCb, failureCb) {
|
|||
.catch(failureCb);
|
||||
}
|
||||
|
||||
export function sendOpen(activeChannelId, successCb, failureCb) {
|
||||
fetch(`/chat_channels/${activeChannelId}/open`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-CSRF-Token': window.csrfToken,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({}),
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(successCb)
|
||||
.catch(failureCb);
|
||||
}
|
||||
|
||||
export function conductModeration(
|
||||
activeChannelId,
|
||||
message,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ const Channels = ({ activeChannelId, chatChannels, handleSwitchChannel }) => {
|
|||
? 'chatchanneltab--active'
|
||||
: 'chatchanneltab--inactive';
|
||||
const name = channel.channel_type === "direct" ? '@'+channel.slug.replace(`${window.currentUser.username}/`, '').replace(`/${window.currentUser.username}`, '') : channel.channel_name
|
||||
const newMessagesIndicatorClass = new Date(channel.last_opened_at) < new Date(channel.last_message_at) ? "chatchanneltabindicator--new" : "chatchanneltabindicator--old"
|
||||
return (
|
||||
<button
|
||||
className='chatchanneltabbutton'
|
||||
|
|
@ -20,7 +21,7 @@ const Channels = ({ activeChannelId, chatChannels, handleSwitchChannel }) => {
|
|||
data-channel-id={channel.id}
|
||||
data-channel-name={name}
|
||||
>
|
||||
{name}
|
||||
<span className={"chatchanneltabindicator " + newMessagesIndicatorClass}></span> {name}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { h, Component } from 'preact';
|
||||
import PropTypes from 'prop-types';
|
||||
import { conductModeration, getAllMessages, sendMessage } from './actions';
|
||||
import { conductModeration, getAllMessages, sendMessage, sendOpen } from './actions';
|
||||
import { hideMessages, scrollToBottom, setupObserver } from './util';
|
||||
import Alert from './alert';
|
||||
import Channels from './channels';
|
||||
|
|
@ -54,6 +54,11 @@ export default class Chat extends Component {
|
|||
channelCleared: this.clearChannel,
|
||||
redactUserMessages: this.redactUserMessages,
|
||||
});
|
||||
sendOpen(
|
||||
this.state.activeChannelId,
|
||||
this.handleChannelOpenSuccess,
|
||||
null,
|
||||
);
|
||||
};
|
||||
|
||||
observerCallback = entries => {
|
||||
|
|
@ -83,8 +88,22 @@ export default class Chat extends Component {
|
|||
this.state.activeChannelId === receivedChatChannelId
|
||||
? { showAlert: this.state.scrolled }
|
||||
: {};
|
||||
const newChannelsObj = this.state.chatChannels.map(channel => {
|
||||
if (receivedChatChannelId === channel["id"]){
|
||||
channel["last_message_at"] = new Date();
|
||||
}
|
||||
return channel;
|
||||
});
|
||||
if (receivedChatChannelId === this.state.activeChannelId) {
|
||||
sendOpen(
|
||||
receivedChatChannelId,
|
||||
this.handleChannelOpenSuccess,
|
||||
null,
|
||||
);
|
||||
}
|
||||
this.setState({
|
||||
...newShowAlert,
|
||||
chatChannels: newChannelsObj,
|
||||
messages: {
|
||||
...this.state.messages,
|
||||
[receivedChatChannelId]: newMessages,
|
||||
|
|
@ -148,6 +167,11 @@ export default class Chat extends Component {
|
|||
showAlert: false,
|
||||
});
|
||||
window.history.replaceState(null, null, "/chat/"+e.target.dataset.channelName);
|
||||
sendOpen(
|
||||
e.target.dataset.channelId,
|
||||
this.handleChannelOpenSuccess,
|
||||
null,
|
||||
);
|
||||
};
|
||||
|
||||
handleSubmitOnClick = e => {
|
||||
|
|
@ -165,6 +189,16 @@ export default class Chat extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
handleChannelOpenSuccess = response => {
|
||||
const newChannelsObj = this.state.chatChannels.map(channel => {
|
||||
if (parseInt(response.channel) === channel["id"]){
|
||||
channel["last_opened_at"] = new Date();
|
||||
}
|
||||
return channel;
|
||||
});
|
||||
this.setState({ chatChannels: newChannelsObj });
|
||||
};
|
||||
|
||||
handleFailure = err => {
|
||||
console.error(err);
|
||||
};
|
||||
|
|
@ -217,6 +251,8 @@ export default class Chat extends Component {
|
|||
</div>
|
||||
);
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="chat">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
class ChatChannel < ApplicationRecord
|
||||
attr_accessor :current_user
|
||||
|
||||
has_many :messages
|
||||
has_many :chat_channel_memberships
|
||||
has_many :users, through: :chat_channel_memberships
|
||||
|
|
@ -18,6 +20,11 @@ class ChatChannel < ApplicationRecord
|
|||
users.include?(user)
|
||||
end
|
||||
|
||||
def last_opened_at(user = nil)
|
||||
user ||= current_user
|
||||
chat_channel_memberships.where(user_id: user.id).pluck(:last_opened_at).first
|
||||
end
|
||||
|
||||
def self.create_with_users(users, channel_type = "direct", contrived_name = "New Channel")
|
||||
raise "Invalid direct channel" if users.size != 2 && channel_type == "direct"
|
||||
if channel_type == "direct"
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
id="chat"
|
||||
class="live-chat"
|
||||
data-pusher-key="<%= ENV["PUSHER_KEY"] %>"
|
||||
data-chat-channels="<%= @chat_channels.to_json %>"
|
||||
data-chat-channels="<%= @chat_channels.to_json(methods: :last_opened_at) %>"
|
||||
data-chat-options="<%= {showChannelsList:true, showTimestamp: true, activeChannelId: @active_channel.id }.to_json %>">
|
||||
</div>
|
||||
<% else %>
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ Rails.application.routes.draw do
|
|||
patch "/onboarding_update" => "users#onboarding_update"
|
||||
get "email_subscriptions/unsubscribe"
|
||||
post "chat_channels/:id/moderate" => "chat_channels#moderate"
|
||||
post "chat_channels/:id/open" => "chat_channels#open"
|
||||
# resources :users
|
||||
|
||||
get "/social_previews/article/:id" => "social_previews#article"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue