Make code work more properly and bind pusher states (#440)
This commit is contained in:
parent
cc45ec8ec6
commit
115ed2e7f7
6 changed files with 113 additions and 73 deletions
|
|
@ -329,6 +329,17 @@
|
|||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.chatchannels__channelslistheader{
|
||||
background: lighten($purple, 5%);
|
||||
border: 1px solid darken($purple, 20%);
|
||||
font-size: 12px;
|
||||
color: $dark-purple;
|
||||
box-sizing: border-box;
|
||||
padding: 5px;
|
||||
width: 98%;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.chatchannels__channelslistfooter{
|
||||
font-size: 12px;
|
||||
color: $medium-gray;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import { h } from 'preact';
|
|||
import PropTypes from 'prop-types';
|
||||
import ConfigImage from 'images/three-dots.svg';
|
||||
|
||||
const Channels = ({ activeChannelId, chatChannels, handleSwitchChannel, expanded }) => {
|
||||
const channels = chatChannels.map(channel => {
|
||||
const Channels = ({ activeChannelId, chatChannels, handleSwitchChannel, expanded, filterQuery, channelsLoaded }) => {
|
||||
const channels = chatChannels.map((channel, index) => {
|
||||
const isActive = parseInt(activeChannelId, 10) === channel.id
|
||||
const lastOpened = channel.last_opened_at ? channel.last_opened_at : channel.channel_users[window.currentUser.username].last_opened_at
|
||||
const isUnopened = new Date(channel.last_message_at) > new Date(lastOpened);
|
||||
const isUnopened = (new Date(channel.last_message_at) > new Date(lastOpened)) && channel.messages_count > 0;
|
||||
|
||||
const otherClassname =
|
||||
isActive
|
||||
|
|
@ -50,7 +50,6 @@ const Channels = ({ activeChannelId, chatChannels, handleSwitchChannel, expanded
|
|||
content = name
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
key={channel.id}
|
||||
|
|
@ -73,9 +72,19 @@ const Channels = ({ activeChannelId, chatChannels, handleSwitchChannel, expanded
|
|||
if (channels.length === 30) {
|
||||
channelsListFooter = <div className="chatchannels__channelslistfooter">You may connect devs you mutually follow. Use the filter to discover all your channels.</div>
|
||||
}
|
||||
let topNotice = ''
|
||||
if (expanded &&
|
||||
filterQuery.length === 0 &&
|
||||
channelsLoaded &&
|
||||
(channels.length === 0 || channels[0].messages_count === 0) ) {
|
||||
topNotice = <div className="chatchannels__channelslistheader">
|
||||
👋 Welcome to <b>DEV Connect</b>! You can may chat with anyone you mutually follow.
|
||||
</div>
|
||||
}
|
||||
return (
|
||||
<div className="chatchannels">
|
||||
<div className="chatchannels__channelslist">
|
||||
{topNotice}
|
||||
{channels}
|
||||
{channelsListFooter}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ export default class Chat extends Component {
|
|||
scrolled: false,
|
||||
showAlert: false,
|
||||
chatChannels,
|
||||
filterQuery: '',
|
||||
channelsLoaded: false,
|
||||
activeChannelId: chatOptions.activeChannelId,
|
||||
activeChannel: null,
|
||||
showChannelsList: chatOptions.showChannelsList,
|
||||
|
|
@ -33,6 +35,7 @@ export default class Chat extends Component {
|
|||
activeContent: null,
|
||||
expanded: window.innerWidth > 600,
|
||||
isMobileDevice: typeof window.orientation !== "undefined",
|
||||
subscribedPusherChannels: []
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -42,22 +45,11 @@ export default class Chat extends Component {
|
|||
this.setupChannel(channel.id);
|
||||
}
|
||||
if (channel.channel_type === "open") {
|
||||
setupPusher(this.props.pusherKey, {
|
||||
channelId: `open-channel-${channel.id}`,
|
||||
messageCreated: this.receiveNewMessage,
|
||||
channelCleared: this.clearChannel,
|
||||
redactUserMessages: this.redactUserMessages,
|
||||
liveCoding: null
|
||||
});
|
||||
this.subscribePusher(`open-channel-${channel.id}`)
|
||||
}
|
||||
});
|
||||
setupObserver(this.observerCallback);
|
||||
setupPusher(this.props.pusherKey, {
|
||||
channelId: `private-message-notifications-${window.currentUser.id}`,
|
||||
messageCreated: this.receiveNewMessage,
|
||||
channelCleared: this.clearChannel,
|
||||
redactUserMessages: this.redactUserMessages,
|
||||
});
|
||||
this.subscribePusher(`private-message-notifications-${window.currentUser.id}`)
|
||||
if (this.state.activeChannelId) {
|
||||
sendOpen(
|
||||
this.state.activeChannelId,
|
||||
|
|
@ -83,22 +75,57 @@ export default class Chat extends Component {
|
|||
}
|
||||
|
||||
liveCoding = e => {
|
||||
if (this.state.activeContent === {type_of: "code_editor"}) {
|
||||
return
|
||||
if (this.state.activeContent != {type_of: "code_editor"}) {
|
||||
this.setState({activeContent: {type_of: "code_editor"}})
|
||||
}
|
||||
if (document.querySelector(".CodeMirror")) {
|
||||
let cm = document.querySelector(".CodeMirror").CodeMirror
|
||||
if (cm && e.context === 'initializing-live-code-channel') {
|
||||
window.pusher.channel(e.channel).trigger('client-livecode', {
|
||||
value: cm.getValue(),
|
||||
cursorPos: cm.getCursor(),
|
||||
});
|
||||
} else if (cm && e.keyPressed === true || e.value.length > 0) {
|
||||
const cursorCoords = e.cursorPos
|
||||
const cursorElement = document.createElement('span');
|
||||
cursorElement.classList.add("cursorelement")
|
||||
cursorElement.style.height = `${(cursorCoords.bottom - cursorCoords.top)}px`;
|
||||
cm.setValue(e.value);
|
||||
cm.setBookmark(e.cursorPos, { widget: cursorElement });
|
||||
}
|
||||
}
|
||||
this.setState({activeContent: {type_of: "code_editor"}})
|
||||
}
|
||||
|
||||
|
||||
filterForActiveChannel = (channels, id) => {
|
||||
return channels.filter(channel => channel.id === parseInt(id))[0]
|
||||
}
|
||||
|
||||
subscribePusher = channelName => {
|
||||
if (this.state.subscribedPusherChannels.includes(channelName)){
|
||||
return
|
||||
} else {
|
||||
setupPusher(this.props.pusherKey, {
|
||||
channelId: channelName,
|
||||
messageCreated: this.receiveNewMessage,
|
||||
channelCleared: this.clearChannel,
|
||||
redactUserMessages: this.redactUserMessages,
|
||||
channelError: this.channelError,
|
||||
liveCoding: this.liveCoding,
|
||||
});
|
||||
let subscriptions = this.state.subscribedPusherChannels;
|
||||
subscriptions.push(channelName);
|
||||
this.setState({subscribedPusherChannels:subscriptions})
|
||||
}
|
||||
}
|
||||
|
||||
loadChannels = (channels, query) => {
|
||||
if (this.state.activeChannelId && query.length === 0) {
|
||||
this.setupChannel(this.state.activeChannelId);
|
||||
this.setState({
|
||||
chatChannels: channels,
|
||||
scrolled: false,
|
||||
channelsLoaded: true,
|
||||
activeChannel: this.filterForActiveChannel(channels, this.state.activeChannelId)
|
||||
});
|
||||
} if (this.state.activeChannelId) {
|
||||
|
|
@ -106,10 +133,13 @@ export default class Chat extends Component {
|
|||
this.setState({
|
||||
scrolled: false,
|
||||
chatChannels: channels,
|
||||
channelsLoaded: true,
|
||||
filterQuery: query
|
||||
});
|
||||
} else {
|
||||
} else if (channels.length > 0) {
|
||||
this.setState({
|
||||
chatChannels: channels,
|
||||
channelsLoaded: true,
|
||||
scrolled: false,
|
||||
});
|
||||
const channel = channels[0]
|
||||
|
|
@ -117,19 +147,15 @@ export default class Chat extends Component {
|
|||
'@'+channel.slug.replace(`${window.currentUser.username}/`, '').replace(`/${window.currentUser.username}`, '') :
|
||||
channel.slug
|
||||
this.triggerSwitchChannel(channel.id, channelSlug);
|
||||
} else {
|
||||
this.setState({channelsLoaded: true})
|
||||
}
|
||||
channels.forEach((channel, index) => {
|
||||
if ( index < 3 ) {
|
||||
this.setupChannel(channel.id);
|
||||
}
|
||||
if (channel.channel_type === "invite_only"){
|
||||
setupPusher(this.props.pusherKey, {
|
||||
channelId: `presence-channel-${channel.id}`,
|
||||
messageCreated: this.receiveNewMessage,
|
||||
channelCleared: this.clearChannel,
|
||||
redactUserMessages: this.redactUserMessages,
|
||||
liveCoding: this.liveCoding
|
||||
});
|
||||
this.subscribePusher(`presence-channel-${channel.id}`)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -139,13 +165,7 @@ export default class Chat extends Component {
|
|||
this.state.messages[channelId][0].reception_method === 'pushed'){
|
||||
getAllMessages(channelId, this.receiveAllMessages);
|
||||
}
|
||||
setupPusher(this.props.pusherKey, {
|
||||
channelId: `presence-channel-${channelId}`,
|
||||
messageCreated: this.receiveNewMessage,
|
||||
channelCleared: this.clearChannel,
|
||||
redactUserMessages: this.redactUserMessages,
|
||||
liveCoding: this.liveCoding
|
||||
});
|
||||
this.subscribePusher(`presence-channel-${channelId}`)
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -159,6 +179,12 @@ export default class Chat extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
channelError = error => {
|
||||
this.setState({
|
||||
subscribedPusherChannels: [],
|
||||
})
|
||||
}
|
||||
|
||||
receiveAllMessages = res => {
|
||||
const { chatChannelId, messages } = res;
|
||||
const newMessages = { ...this.state.messages, [chatChannelId]: messages };
|
||||
|
|
@ -416,6 +442,8 @@ export default class Chat extends Component {
|
|||
activeChannelId={this.state.activeChannelId}
|
||||
chatChannels={this.state.chatChannels}
|
||||
handleSwitchChannel={this.handleSwitchChannel}
|
||||
channelsLoaded={this.state.channelsLoaded}
|
||||
filterQuery={this.state.filterQuery}
|
||||
expanded={this.state.expanded}
|
||||
/>
|
||||
{notificationsState}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { h, Component } from 'preact';
|
||||
import PropTypes from 'prop-types';
|
||||
import setupPusher from '../src/utils/pusher';
|
||||
import CodeMirror from 'codemirror';
|
||||
import 'codemirror/mode/javascript/javascript';
|
||||
import 'codemirror/mode/jsx/jsx';
|
||||
|
|
@ -10,10 +9,6 @@ export default class CodeEditor extends Component {
|
|||
|
||||
componentDidMount() {
|
||||
const editor = document.getElementById("codeeditor");
|
||||
const channel = setupPusher(this.props.pusherKey, {
|
||||
channelId: `presence-channel-${this.props.activeChannelId}`,
|
||||
liveCoding: this.liveCoding,
|
||||
});
|
||||
const myCodeMirror = CodeMirror(editor, {
|
||||
mode: "javascript",
|
||||
theme: "material",
|
||||
|
|
@ -21,9 +16,10 @@ export default class CodeEditor extends Component {
|
|||
});
|
||||
myCodeMirror.setSize("100%", "100%");
|
||||
//Initial trigger:
|
||||
const channel = window.pusher.channel(`presence-channel-${this.props.activeChannelId}`)
|
||||
channel.trigger('client-livecode', {
|
||||
value: myCodeMirror.getValue(),
|
||||
cursorPos: myCodeMirror.getCursor(),
|
||||
context: 'initializing-live-code-channel',
|
||||
channel: `presence-channel-${this.props.activeChannelId}`
|
||||
});
|
||||
//Coding trigger:
|
||||
myCodeMirror.on('keyup', cm => {
|
||||
|
|
@ -38,24 +34,6 @@ export default class CodeEditor extends Component {
|
|||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
liveCoding = e => {
|
||||
if (e.keyPressed === true || e.value.length > 0) {
|
||||
let cm = document.querySelector(".CodeMirror").CodeMirror
|
||||
const cursorCoords = e.cursorPos
|
||||
const cursorElement = document.createElement('span');
|
||||
cursorElement.classList.add("cursorelement")
|
||||
cursorElement.style.height = `${(cursorCoords.bottom - cursorCoords.top)}px`;
|
||||
cm.setValue(e.value);
|
||||
cm.setBookmark(e.cursorPos, { widget: cursorElement });
|
||||
} else {
|
||||
let cm = document.querySelector(".CodeMirror").CodeMirror
|
||||
channel.trigger('client-livecode', {
|
||||
value: cm.getValue(),
|
||||
cursorPos: cm.getCursor(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,29 @@
|
|||
import Pusher from 'pusher-js';
|
||||
|
||||
export default function setupPusher(key, callbackObjects) {
|
||||
const pusher = new Pusher(key, {
|
||||
authEndpoint: '/pusher/auth',
|
||||
auth: {
|
||||
headers: {
|
||||
'X-CSRF-Token': window.csrfToken
|
||||
}
|
||||
},
|
||||
cluster: 'us2',
|
||||
encrypted: true,
|
||||
});
|
||||
pusher.unsubscribe(callbackObjects.channelId.toString());
|
||||
let pusher;
|
||||
if (window.pusher) {
|
||||
pusher = window.pusher
|
||||
} else {
|
||||
pusher = new Pusher(key, {
|
||||
authEndpoint: '/pusher/auth',
|
||||
auth: {
|
||||
headers: {
|
||||
'X-CSRF-Token': window.csrfToken
|
||||
}
|
||||
},
|
||||
cluster: 'us2',
|
||||
encrypted: true,
|
||||
});
|
||||
window.pusher = pusher;
|
||||
}
|
||||
const channel = pusher.subscribe(callbackObjects.channelId.toString());
|
||||
channel.bind('message-created', callbackObjects.messageCreated);
|
||||
channel.bind('channel-cleared', callbackObjects.channelCleared);
|
||||
channel.bind('user-banned', callbackObjects.redactUserMessages);
|
||||
channel.bind('client-livecode', callbackObjects.liveCoding);
|
||||
// channel.bind('pusher:subscription_succeeded', callbackObjects.channelSubscribed);
|
||||
channel.bind('pusher:subscription_error', callbackObjects.channelError);
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ class ChatChannel < ApplicationRecord
|
|||
|
||||
algoliasearch index_name: "SecuredChatChannel_#{Rails.env}" do
|
||||
attribute :id, :viewable_by, :slug, :channel_type,
|
||||
:channel_name, :channel_users, :last_message_at, :status
|
||||
:channel_name, :channel_users, :last_message_at, :status,
|
||||
:messages_count
|
||||
searchableAttributes [:channel_name,:channel_slug]
|
||||
attributesForFaceting ["filterOnly(viewable_by)","filterOnly(status)"]
|
||||
ranking ["desc(last_message_at)"]
|
||||
|
|
@ -57,6 +58,7 @@ class ChatChannel < ApplicationRecord
|
|||
status: "active",
|
||||
)
|
||||
channel.add_users(users)
|
||||
channel.index!
|
||||
end
|
||||
channel
|
||||
end
|
||||
|
|
@ -93,6 +95,10 @@ class ChatChannel < ApplicationRecord
|
|||
chat_channel_memberships.pluck(:user_id)
|
||||
end
|
||||
|
||||
def messages_count
|
||||
messages.size
|
||||
end
|
||||
|
||||
def channel_users
|
||||
pics_obj = {}
|
||||
chat_channel_memberships.includes(:user).each do |m|
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue