mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 02:24:16 +00:00
update: ng-server, messaging
This commit is contained in:
parent
ebddfbcb6e
commit
5afe18754f
1
.gitignore
vendored
1
.gitignore
vendored
@ -22,3 +22,4 @@ package-lock.json
|
||||
src/locales/_build
|
||||
src/locales/**/*.js
|
||||
android/
|
||||
direct
|
@ -1,5 +1,4 @@
|
||||
module.exports = {
|
||||
server_endpoint: 'https://comty.julioworld.club',
|
||||
siteName: 'Comty',
|
||||
copyright: 'RageStudio©',
|
||||
|
||||
@ -9,7 +8,8 @@ module.exports = {
|
||||
DarkLogoPath: '/dark_logo.svg',
|
||||
|
||||
resource_bundle: 'light_ng',
|
||||
sync_server: 'http://eu653-node.ragestudio.net:5500',
|
||||
sync_server: 'http://localhost:5500',
|
||||
server_endpoint: 'https://comty.pw',
|
||||
|
||||
g_recaptcha_key: '6Lc55uUUAAAAAEIACMVf3BUzAJSNCmI3RrjEirZ6',
|
||||
g_recaptcha_secret: '6Lc55uUUAAAAAOP4OgUa5DpqJC-70t53AmW0lyYf',
|
||||
|
@ -1,23 +0,0 @@
|
||||
module.exports = {
|
||||
Endpoints: {
|
||||
comments_actions: "https://api.ragestudio.net/RSA-COMTY/r/comments?access_token=",
|
||||
get_post_data: "https://api.ragestudio.net/RSA-COMTY/r/get-post-data?access_token=",
|
||||
get_user_tags: "https://api.ragestudio.net/RSA-COMTY/r/user_tags?access_token=",
|
||||
get_general_data: "https://api.ragestudio.net/RSA-COMTY/r/get-general-data?access_token=",
|
||||
follow_user: "https://api.ragestudio.net/RSA-COMTY/r/follow-user?access_token=",
|
||||
action_post: "https://api.ragestudio.net/RSA-COMTY/r/post-actions?access_token=",
|
||||
get_posts: "https://api.ragestudio.net/RSA-COMTY/r/posts?access_token=",
|
||||
find_user: "https://api.ragestudio.net/RSA-COMTY/r/find_user?access_token=",
|
||||
search_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/search?access_token=",
|
||||
all_sessions: "https://api.ragestudio.net/RSA-COMTY/r/sessions?access_token=",
|
||||
get_sessions: "https://api.ragestudio.net/RSA-COMTY/r/session_id?access_token=",
|
||||
auth_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/auth",
|
||||
new_post: "https://comty.julioworld.club/api/new_post?access_token=",
|
||||
get_config_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/get-site-settings?access_token=",
|
||||
get_userData_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/get-user-data?access_token=",
|
||||
update_userData_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/update-user-data?access_token=",
|
||||
removeToken: "https://api.ragestudio.net/RSA-COMTY/r/delete-access-token?access_token=",
|
||||
register_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/create-account",
|
||||
resetPassword_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/send-reset-password-email?access_token=",
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ module.exports={
|
||||
all_sessions: "https://api.ragestudio.net/RSA-COMTY/r/sessions?access_token=",
|
||||
get_sessions: "https://api.ragestudio.net/RSA-COMTY/r/session_id?access_token=",
|
||||
auth_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/auth",
|
||||
new_post: "https://comty.julioworld.club/api/new_post?access_token=",
|
||||
new_post: "https://comty.pw/api/new_post?access_token=",
|
||||
get_config_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/get-site-settings?access_token=",
|
||||
get_userData: "https://api.ragestudio.net/RSA-COMTY/r/get-user-data?access_token=",
|
||||
update_userData_endpoint: "https://api.ragestudio.net/RSA-COMTY/r/update-user-data?access_token=",
|
||||
|
@ -3,7 +3,7 @@
|
||||
"UUID": "C8mVSr-4nmPp2-pr5Vrz-CU4kg4",
|
||||
"title": "Comty™",
|
||||
"DevBuild": true,
|
||||
"version": "0.3.18",
|
||||
"version": "0.4.02",
|
||||
"stage": "dev-pre",
|
||||
"description": "",
|
||||
"author": "RageStudio",
|
||||
@ -37,8 +37,10 @@
|
||||
"randomstring": "^1.1.5",
|
||||
"react-animations": "^1.0.0",
|
||||
"react-dazzle": "^1.4.0",
|
||||
"react-emoji": "^0.5.0",
|
||||
"react-google-recaptcha": "^2.0.1",
|
||||
"react-helmet": "^5.2.1",
|
||||
"react-linkify": "^1.0.0-alpha",
|
||||
"react-perfect-scrollbar": "^1.5.8",
|
||||
"react-reveal": "^1.2.2",
|
||||
"react-scripts": "^3.4.1",
|
||||
|
@ -1,8 +1,27 @@
|
||||
import { API_Call, endpoints } from 'ycore'
|
||||
import { API_Call, endpoints, get_early } from 'ycore'
|
||||
import { comty_rsa } from '../rs_cloud/pre'
|
||||
|
||||
export const comty_user = {
|
||||
setData: () => {},
|
||||
data: {
|
||||
avatar: (callback,key) => {
|
||||
if(!key) return false
|
||||
|
||||
try {
|
||||
const payload = {username: key}
|
||||
get_early.user((err,res) => {
|
||||
const d = JSON.parse(res)['data']
|
||||
return callback(d.avatar)
|
||||
},payload)
|
||||
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
},
|
||||
getFollowers: (callback, payload) => {
|
||||
if (!payload)return false
|
||||
const { user_id } = payload
|
||||
|
@ -43,13 +43,15 @@ export const sync = {
|
||||
|
||||
},
|
||||
FeedListen: (callback) => {
|
||||
const socket = io(endpoint);
|
||||
const socket = io(`${endpoint}/feed`);
|
||||
|
||||
socket.on('pull_event', function (data) {
|
||||
console.log(data)
|
||||
callback(data)
|
||||
});
|
||||
},
|
||||
emmitPost: (last_id) => {
|
||||
const socket = io(endpoint);
|
||||
const socket = io(`${endpoint}/feed`);
|
||||
socket.emit('push_event', last_id);
|
||||
}
|
||||
}
|
@ -105,7 +105,7 @@
|
||||
padding: 30px 30px 30px 35px;
|
||||
|
||||
color: @secondary_container_1_color;
|
||||
background-color: #2d2d2d;
|
||||
background-color: #F8F6F8;
|
||||
|
||||
|
||||
&.full_open {
|
||||
|
@ -4,9 +4,9 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: @__Global_general_font_family;
|
||||
color: #ffffff;
|
||||
color: #201F23;
|
||||
font-size: 12px;
|
||||
h1,h2,h3,h4,h5{color:#ffffff}
|
||||
h1,h2,h3,h4,h5{color:#201F23}
|
||||
}
|
||||
|
||||
.UserContainer {
|
||||
@ -45,7 +45,7 @@
|
||||
display: flex;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
margin: 0 0 0 50px;
|
||||
color: #ffffff !important;
|
||||
color: #201F23 !important;
|
||||
}
|
||||
|
||||
.textAgo {
|
||||
@ -81,7 +81,7 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
color: #ffffff !important;
|
||||
color: #201F23 !important;
|
||||
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@
|
||||
|
||||
h3 {
|
||||
font-family: "Poppins", sans-serif;
|
||||
color: #ffffff;
|
||||
color: #201F23;
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
letter-spacing: -0.3px;
|
||||
@ -159,7 +159,7 @@
|
||||
overflow-y: scroll!important;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
background-color: #201F23;
|
||||
word-break: break-all;
|
||||
|
||||
.comment_title {
|
||||
@ -202,7 +202,7 @@
|
||||
right: 0;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
background-color: #ffffffd7;
|
||||
background-color: #201F23d7;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 60px;
|
||||
border-radius: 0 0 0 32px;
|
||||
@ -229,7 +229,7 @@
|
||||
}
|
||||
|
||||
.search_wrapper{
|
||||
color: #ffffff;
|
||||
color: #201F23;
|
||||
height: 100%;
|
||||
width: 82%;
|
||||
margin: auto;
|
||||
@ -255,7 +255,7 @@
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
word-break: break-all;
|
||||
color: #ffffff;
|
||||
color: #201F23;
|
||||
cursor: pointer;
|
||||
|
||||
.search_title {
|
||||
@ -272,7 +272,7 @@
|
||||
margin: 0 5px 0 8px;
|
||||
vertical-align: middle;
|
||||
height: 100%;
|
||||
color: #ffffff;
|
||||
color: #201F23;
|
||||
line-height: 25px;
|
||||
}
|
||||
}
|
||||
@ -285,12 +285,12 @@
|
||||
|
||||
.secondary_hastags {
|
||||
font-family: @__Global_general_font_family;
|
||||
color: #ffffff;
|
||||
color: #201F23;
|
||||
font-size: 12px;
|
||||
|
||||
|
||||
.secondary_hastags_title{
|
||||
h2{color: #ffffff;}
|
||||
h2{color: #201F23;}
|
||||
}
|
||||
|
||||
.secondary_hastags_body{
|
||||
@ -336,7 +336,7 @@
|
||||
height: 140px;
|
||||
|
||||
h1{
|
||||
color: #ffffff;
|
||||
color: #201F23;
|
||||
font-family: "Poppins", sans-serif;
|
||||
font-size: 18px;
|
||||
margin-bottom: 0;
|
||||
|
@ -16,8 +16,6 @@ export default class Sider_Default extends React.PureComponent {
|
||||
<div className={styles.left_sider_wrapper}>
|
||||
<antd.Layout.Sider
|
||||
trigger={null}
|
||||
collapsed
|
||||
collapsedWidth='80'
|
||||
className={styles.left_sider_container}
|
||||
>
|
||||
<div className={styles.left_sider_brandholder}>
|
||||
|
@ -20,7 +20,7 @@
|
||||
}
|
||||
|
||||
.ant-menu-item {
|
||||
color: @left_sider_color;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.anticon {
|
||||
@ -129,9 +129,9 @@
|
||||
:global {
|
||||
.ant-menu-item {
|
||||
padding: 0 !important;
|
||||
margin: 2px auto 2px auto;
|
||||
margin: 2px auto 2px 24px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
11
src/pages/chats/Events.js
Normal file
11
src/pages/chats/Events.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
COMMUNITY_CHAT:"COMMUNITY_CHAT",
|
||||
USER_CONNECTED:"USER_CONNECTED",
|
||||
MESSAGE_RECIEVED:"MESSAGE_RECIEVED",
|
||||
MESSAGE_SENT:"MESSAGE_SENT",
|
||||
USER_DISCONNECTED:"USER_DISCONNECTED",
|
||||
TYPING:"TYPING",
|
||||
VERIFY_USER:"VERIFY_USER",
|
||||
LOGOUT:"LOGOUT",
|
||||
PRIVATE_MESSAGE:"PRIVATE_MESSAGE"
|
||||
}
|
183
src/pages/chats/chats/ChatContainer.js
Normal file
183
src/pages/chats/chats/ChatContainer.js
Normal file
@ -0,0 +1,183 @@
|
||||
import React, { Component } from 'react';
|
||||
import SideBar from './SideBar'
|
||||
import { MESSAGE_SENT, MESSAGE_RECIEVED, TYPING, PRIVATE_MESSAGE } from '../Events'
|
||||
import ChatHeading from './ChatHeading'
|
||||
import Messages from '../messages/Messages'
|
||||
import MessageInput from '../messages/MessageInput'
|
||||
import * as ycore from 'ycore'
|
||||
|
||||
const userData = ycore.userData();
|
||||
|
||||
export default class ChatContainer extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
chats:[],
|
||||
activeChat:null
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { socket } = this.props
|
||||
this.initSocket(socket)
|
||||
}
|
||||
|
||||
initSocket(socket){
|
||||
socket.on(PRIVATE_MESSAGE, this.addChat)
|
||||
}
|
||||
|
||||
sendOpenPrivateMessage = (reciever) => {
|
||||
const { socket, user } = this.props
|
||||
const { activeChat } = this.state
|
||||
socket.emit(PRIVATE_MESSAGE, {reciever, sender:user.name, activeChat})
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the chat back to only the chat passed in.
|
||||
* @param chat {Chat}
|
||||
*/
|
||||
resetChat = (chat)=>{
|
||||
return this.addChat(chat, true)
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds chat to the chat container, if reset is true removes all chats
|
||||
* and sets that chat to the main chat.
|
||||
* Sets the message and typing socket events for the chat.
|
||||
*
|
||||
* @param chat {Chat} the chat to be added.
|
||||
* @param reset {boolean} if true will set the chat as the only chat.
|
||||
*/
|
||||
addChat = (chat, reset = false)=>{
|
||||
const { socket } = this.props
|
||||
const { chats } = this.state
|
||||
|
||||
console.log(chat)
|
||||
|
||||
const newChats = reset ? [chat] : [...chats, chat]
|
||||
this.setState({chats:newChats, activeChat:reset ? chat : this.state.activeChat})
|
||||
|
||||
const messageEvent = `${MESSAGE_RECIEVED}-${chat.id}`
|
||||
const typingEvent = `${TYPING}-${chat.id}`
|
||||
|
||||
socket.on(typingEvent, this.updateTypingInChat(chat.id))
|
||||
socket.on(messageEvent, this.addMessageToChat(chat.id))
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a function that will
|
||||
* adds message to chat with the chatId passed in.
|
||||
*
|
||||
* @param chatId {number}
|
||||
*/
|
||||
addMessageToChat = (chatId)=>{
|
||||
return message => {
|
||||
const { chats } = this.state
|
||||
let newChats = chats.map((chat)=>{
|
||||
if(chat.id === chatId)
|
||||
chat.messages.push(message)
|
||||
return chat
|
||||
})
|
||||
|
||||
this.setState({chats:newChats})
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the typing of chat with id passed in.
|
||||
* @param chatId {number}
|
||||
*/
|
||||
updateTypingInChat = (chatId) =>{
|
||||
return ({isTyping, user})=>{
|
||||
if(user !== this.props.user.name){
|
||||
|
||||
const { chats } = this.state
|
||||
|
||||
let newChats = chats.map((chat)=>{
|
||||
if(chat.id === chatId){
|
||||
if(isTyping && !chat.typingUsers.includes(user)){
|
||||
chat.typingUsers.push(user)
|
||||
}else if(!isTyping && chat.typingUsers.includes(user)){
|
||||
chat.typingUsers = chat.typingUsers.filter(u => u !== user)
|
||||
}
|
||||
}
|
||||
return chat
|
||||
})
|
||||
this.setState({chats:newChats})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a message to the specified chat
|
||||
* @param chatId {number} The id of the chat to be added to.
|
||||
* @param message {string} The message to be added to the chat.
|
||||
*/
|
||||
sendMessage = (chatId, message)=>{
|
||||
const { socket } = this.props
|
||||
socket.emit(MESSAGE_SENT, {chatId, message} )
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends typing status to server.
|
||||
* chatId {number} the id of the chat being typed in.
|
||||
* typing {boolean} If the user is typing still or not.
|
||||
*/
|
||||
sendTyping = (chatId, isTyping)=>{
|
||||
const { socket } = this.props
|
||||
socket.emit(TYPING, {chatId, isTyping})
|
||||
}
|
||||
|
||||
setActiveChat = (activeChat)=>{
|
||||
this.setState({activeChat})
|
||||
}
|
||||
render() {
|
||||
const { user, logout } = this.props
|
||||
const { chats, activeChat } = this.state
|
||||
return (
|
||||
<div className="container">
|
||||
<SideBar
|
||||
chats={chats}
|
||||
user={user}
|
||||
activeChat={activeChat}
|
||||
setActiveChat={this.setActiveChat}
|
||||
onSendPrivateMessage={this.sendOpenPrivateMessage}
|
||||
/>
|
||||
<div className="chat-room-container">
|
||||
{
|
||||
activeChat !== null ? (
|
||||
|
||||
<div className="chat-room">
|
||||
<ChatHeading name={activeChat.name} />
|
||||
<Messages
|
||||
messages={activeChat.messages}
|
||||
user={user}
|
||||
typingUsers={activeChat.typingUsers}
|
||||
/>
|
||||
<MessageInput
|
||||
sendMessage={
|
||||
(message)=>{
|
||||
this.sendMessage(activeChat.id, message)
|
||||
}
|
||||
}
|
||||
sendTyping={
|
||||
(isTyping)=>{
|
||||
this.sendTyping(activeChat.id, isTyping)
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
</div>
|
||||
):
|
||||
<div className="chat-room choose">
|
||||
<h3>Choose a chat!</h3>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
18
src/pages/chats/chats/ChatHeading.js
Normal file
18
src/pages/chats/chats/ChatHeading.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
|
||||
export default function({name, numberOfUsers}) {
|
||||
|
||||
return (
|
||||
<div className="chat-header">
|
||||
<div className="user-info">
|
||||
<div className="user-name">{name}</div>
|
||||
<div className="status">
|
||||
<div className="indicator"></div>
|
||||
<span>{numberOfUsers ? numberOfUsers : null}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
80
src/pages/chats/chats/SideBar.js
Normal file
80
src/pages/chats/chats/SideBar.js
Normal file
@ -0,0 +1,80 @@
|
||||
import React, { Component } from 'react';
|
||||
import * as ycore from 'ycore'
|
||||
import * as antd from 'antd'
|
||||
|
||||
const userData = ycore.userData()
|
||||
|
||||
export default class SideBar extends React.PureComponent{
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {
|
||||
reciever:""
|
||||
}
|
||||
}
|
||||
handleSubmit = (e) => {
|
||||
e.preventDefault()
|
||||
const { reciever } = this.state
|
||||
const { onSendPrivateMessage } = this.props
|
||||
|
||||
onSendPrivateMessage(reciever)
|
||||
this.setState({reciever:""})
|
||||
}
|
||||
|
||||
render(){
|
||||
const { chats, activeChat, user, setActiveChat } = this.props
|
||||
const { reciever } = this.state
|
||||
|
||||
return (
|
||||
<div id="side-bar">
|
||||
|
||||
<form onSubmit={this.handleSubmit} className="search">
|
||||
<input
|
||||
placeholder="Search"
|
||||
type="text"
|
||||
value={reciever}
|
||||
onChange={(e)=>{ this.setState({reciever:e.target.value}) }}/>
|
||||
</form>
|
||||
|
||||
<div
|
||||
className="users"
|
||||
ref='users'
|
||||
onClick={(e)=>{ (e.target === this.refs.user) && setActiveChat(null) }}>
|
||||
|
||||
{
|
||||
chats.map((chat)=>{
|
||||
if(chat.name){
|
||||
const lastMessage = chat.messages[chat.messages.length - 1];
|
||||
const chatSideName = chat.users.find((name)=>{
|
||||
return name !== user.name
|
||||
}) || "Unknown"
|
||||
const ops_adata = chat.udata.find((i) =>{
|
||||
return i.user !== user.name? i.avatar : null
|
||||
})
|
||||
const classNames = (activeChat && activeChat.id === chat.id) ? 'active' : ''
|
||||
return(
|
||||
<div
|
||||
key={chat.id}
|
||||
className={`user ${classNames}`}
|
||||
onClick={ ()=>{ setActiveChat(chat) } }
|
||||
>
|
||||
<div className="user-photo"> <antd.Avatar size="small" src={ops_adata.avatar} /> </div>
|
||||
<div className="user-info">
|
||||
<div className="name">{chatSideName}</div>
|
||||
{lastMessage && <div className="last-message">{lastMessage.message}</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
})
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
}
|
@ -1,9 +1,82 @@
|
||||
import React from 'react'
|
||||
import * as ycore from 'ycore'
|
||||
import * as antd from 'antd'
|
||||
import * as Icons from '@ant-design/icons'
|
||||
import io from 'socket.io-client'
|
||||
import config from 'config'
|
||||
import ReactEmoji from 'react-emoji';
|
||||
import { USER_CONNECTED, LOGOUT } from './Events'
|
||||
import ChatContainer from './chats/ChatContainer'
|
||||
|
||||
export default class extends React.PureComponent{
|
||||
render(){
|
||||
return(
|
||||
<div>Chats</div>
|
||||
)
|
||||
|
||||
const userData = ycore.userData()
|
||||
|
||||
const prefix = '[Messaging Socket] '
|
||||
const socketUrl = io(`${config.sync_server}/messaging_socket`);
|
||||
|
||||
export default class Chats extends React.Component{
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
socket:null,
|
||||
user:null,
|
||||
conn: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.initSocket()
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to and initializes the socket.
|
||||
*/
|
||||
initSocket = async ()=>{
|
||||
const socket = socketUrl
|
||||
|
||||
if(!this.state.conn){
|
||||
await socket.on('connect', ()=>{
|
||||
console.log(prefix, "Connected");
|
||||
this.setState({ conn: true })
|
||||
const payload = { id: userData.UserID, name: userData.username, avatar: userData.avatar }
|
||||
this.setUser(payload)
|
||||
})
|
||||
}
|
||||
|
||||
this.setState({socket})
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
this.setState({ conn: false })
|
||||
})
|
||||
|
||||
socket.on('reconnecting', () =>{
|
||||
console.log(prefix, 'Trying to reconnect')
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the user property in state
|
||||
* @param user {id:number, name:string}
|
||||
*/
|
||||
setUser = (user)=>{
|
||||
const { socket } = this.state
|
||||
socket.emit(USER_CONNECTED, user);
|
||||
this.setState({user})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { socket, user } = this.state
|
||||
return (
|
||||
<div className="container">
|
||||
{
|
||||
!user ?
|
||||
<h2>initializes....</h2>
|
||||
:
|
||||
<ChatContainer socket={socket} user={user} />
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
100
src/pages/chats/messages/MessageInput.js
Normal file
100
src/pages/chats/messages/MessageInput.js
Normal file
@ -0,0 +1,100 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
export default class MessageInput extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
message:"",
|
||||
isTyping:false
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
handleSubmit = (e)=>{
|
||||
e.preventDefault()
|
||||
this.sendMessage()
|
||||
this.setState({message:""})
|
||||
}
|
||||
|
||||
sendMessage = ()=>{
|
||||
this.props.sendMessage(this.state.message)
|
||||
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.stopCheckingTyping()
|
||||
}
|
||||
|
||||
sendTyping = ()=>{
|
||||
this.lastUpdateTime = Date.now()
|
||||
if(!this.state.isTyping){
|
||||
this.setState({isTyping:true})
|
||||
this.props.sendTyping(true)
|
||||
this.startCheckingTyping()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* startCheckingTyping
|
||||
* Start an interval that checks if the user is typing.
|
||||
*/
|
||||
startCheckingTyping = ()=>{
|
||||
console.log("Typing");
|
||||
this.typingInterval = setInterval(()=>{
|
||||
if((Date.now() - this.lastUpdateTime) > 300){
|
||||
this.setState({isTyping:false})
|
||||
this.stopCheckingTyping()
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
|
||||
/*
|
||||
* stopCheckingTyping
|
||||
* Start the interval from checking if the user is typing.
|
||||
*/
|
||||
stopCheckingTyping = ()=>{
|
||||
console.log("Stop Typing");
|
||||
if(this.typingInterval){
|
||||
clearInterval(this.typingInterval)
|
||||
this.props.sendTyping(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { message } = this.state
|
||||
return (
|
||||
<div className="message-input">
|
||||
<form
|
||||
onSubmit={ this.handleSubmit }
|
||||
className="message-form">
|
||||
|
||||
<input
|
||||
id = "message"
|
||||
ref = {"messageinput"}
|
||||
type = "text"
|
||||
className = "form-control"
|
||||
value = { message }
|
||||
autoComplete = {'off'}
|
||||
placeholder = "Type something interesting"
|
||||
onKeyUp = { e => { e.keyCode !== 13 && this.sendTyping() } }
|
||||
onChange = {
|
||||
({target})=>{
|
||||
this.setState({message:target.value})
|
||||
}
|
||||
}
|
||||
/>
|
||||
<button
|
||||
disabled = { message.length < 1 }
|
||||
type = "submit"
|
||||
className = "send"
|
||||
|
||||
> Send </button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
61
src/pages/chats/messages/Messages.js
Normal file
61
src/pages/chats/messages/Messages.js
Normal file
@ -0,0 +1,61 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
export default class Messages extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.scrollDown = this.scrollDown.bind(this)
|
||||
}
|
||||
|
||||
scrollDown(){
|
||||
const { container } = this.refs
|
||||
container.scrollTop = container.scrollHeight
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.scrollDown()
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
this.scrollDown()
|
||||
}
|
||||
|
||||
render() {
|
||||
const { messages, user, typingUsers } = this.props
|
||||
return (
|
||||
<div ref='container'
|
||||
className="thread-container">
|
||||
<div className="thread">
|
||||
{
|
||||
messages.map((mes)=>{
|
||||
return (
|
||||
<div
|
||||
key={mes.id}
|
||||
className={`message-container ${mes.sender === user.name && 'right'}`}
|
||||
>
|
||||
<div className="time">{mes.time}</div>
|
||||
<div className="data">
|
||||
<div className="message">{mes.message}</div>
|
||||
<div className="name">{mes.sender}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
})
|
||||
}
|
||||
{
|
||||
typingUsers.map((name)=>{
|
||||
return (
|
||||
<div key={name} className="typing-user">
|
||||
{`${name} is typing . . .`}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -128,7 +128,7 @@ body {
|
||||
// }
|
||||
|
||||
// .primary_layout_*
|
||||
@primary_layout_backgroud: #2d2d2d;
|
||||
@primary_layout_backgroud: #F8F6F8; // #2d2d2d;
|
||||
|
||||
@primary_layout_container_backgroud: @__Global_layout_backgroud;
|
||||
@primary_layout_container_border-rd: @__Global_layout_border-rd;
|
||||
@ -140,8 +140,8 @@ body {
|
||||
@secondary_wrapper_hidden_width: 22vw;
|
||||
@secondary_wrapper_showFull_width: 94.2%;
|
||||
@secondary_wrapper_showHalf_width: 35vw;
|
||||
@secondary_container_bg_background: #201F23;
|
||||
@secondary_container_1_color: #fff;
|
||||
@secondary_container_bg_background: #F8F6F8;
|
||||
@secondary_container_1_color: #201F23;
|
||||
@secondary_container_2_color: #201F23;
|
||||
@secondary_container_2_backgroud: #fff;
|
||||
@secondary_container_1_btn_backgroud: #4c4c4c;
|
||||
@ -152,7 +152,7 @@ body {
|
||||
@secondaty_container_2_padding: 20px 15px 15px 15px;
|
||||
|
||||
// .left_sider*
|
||||
@left_sider_backgroud: #2d2d2d;
|
||||
@left_sider_backgroud: #F8F6F8;
|
||||
@left_sider_color: #fff;
|
||||
@left_sider_sizeIcons: 19px;
|
||||
@left_sider_menu__onhover_backgroud: rgb(80, 80, 80);
|
||||
|
Loading…
x
Reference in New Issue
Block a user