From 5afe18754f5676b4ecb160f8ab5fdd313bc0a908 Mon Sep 17 00:00:00 2001 From: srgooglo <38926803+srgooglo@users.noreply.github.com> Date: Sat, 2 May 2020 19:27:45 +0200 Subject: [PATCH] update: ng-server, messaging --- .gitignore | 1 + config/ycore.config.js | 4 +- globals/endpoints.js | 23 --- globals/endpoints/comty_endpoints.js | 2 +- package.json | 4 +- src/@ycore/libs/comty_ng/comty_user.js | 21 ++- src/@ycore/libs/ycore_sync/pre.js | 6 +- src/components/Layout/Secondary/index.less | 2 +- src/components/Layout/Secondary/renders.less | 26 +-- src/components/Layout/Sider/default.js | 2 - src/components/Layout/Sider/default.less | 6 +- src/pages/chats/Events.js | 11 ++ src/pages/chats/chats/ChatContainer.js | 183 +++++++++++++++++++ src/pages/chats/chats/ChatHeading.js | 18 ++ src/pages/chats/chats/SideBar.js | 80 ++++++++ src/pages/chats/index.js | 83 ++++++++- src/pages/chats/messages/MessageInput.js | 100 ++++++++++ src/pages/chats/messages/Messages.js | 61 +++++++ src/themes/base/index.less | 8 +- 19 files changed, 583 insertions(+), 58 deletions(-) delete mode 100755 globals/endpoints.js create mode 100644 src/pages/chats/Events.js create mode 100644 src/pages/chats/chats/ChatContainer.js create mode 100644 src/pages/chats/chats/ChatHeading.js create mode 100644 src/pages/chats/chats/SideBar.js create mode 100644 src/pages/chats/messages/MessageInput.js create mode 100644 src/pages/chats/messages/Messages.js diff --git a/.gitignore b/.gitignore index 500b786a..08f11a0e 100755 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ package-lock.json src/locales/_build src/locales/**/*.js android/ +direct \ No newline at end of file diff --git a/config/ycore.config.js b/config/ycore.config.js index b6383eb2..47ae6307 100755 --- a/config/ycore.config.js +++ b/config/ycore.config.js @@ -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', diff --git a/globals/endpoints.js b/globals/endpoints.js deleted file mode 100755 index 7ddc39e1..00000000 --- a/globals/endpoints.js +++ /dev/null @@ -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=", - } -} \ No newline at end of file diff --git a/globals/endpoints/comty_endpoints.js b/globals/endpoints/comty_endpoints.js index 45338a71..a30ab6e0 100755 --- a/globals/endpoints/comty_endpoints.js +++ b/globals/endpoints/comty_endpoints.js @@ -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=", diff --git a/package.json b/package.json index 72254fc6..ff7118b3 100755 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/@ycore/libs/comty_ng/comty_user.js b/src/@ycore/libs/comty_ng/comty_user.js index 92ed9ded..bd10a5fe 100755 --- a/src/@ycore/libs/comty_ng/comty_user.js +++ b/src/@ycore/libs/comty_ng/comty_user.js @@ -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 diff --git a/src/@ycore/libs/ycore_sync/pre.js b/src/@ycore/libs/ycore_sync/pre.js index 734c9fba..465cce8e 100755 --- a/src/@ycore/libs/ycore_sync/pre.js +++ b/src/@ycore/libs/ycore_sync/pre.js @@ -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); } } \ No newline at end of file diff --git a/src/components/Layout/Secondary/index.less b/src/components/Layout/Secondary/index.less index 45f0e78b..1227b926 100755 --- a/src/components/Layout/Secondary/index.less +++ b/src/components/Layout/Secondary/index.less @@ -105,7 +105,7 @@ padding: 30px 30px 30px 35px; color: @secondary_container_1_color; - background-color: #2d2d2d; + background-color: #F8F6F8; &.full_open { diff --git a/src/components/Layout/Secondary/renders.less b/src/components/Layout/Secondary/renders.less index 9b5369b7..01faa713 100755 --- a/src/components/Layout/Secondary/renders.less +++ b/src/components/Layout/Secondary/renders.less @@ -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; diff --git a/src/components/Layout/Sider/default.js b/src/components/Layout/Sider/default.js index 6a4cde7e..4244f705 100755 --- a/src/components/Layout/Sider/default.js +++ b/src/components/Layout/Sider/default.js @@ -16,8 +16,6 @@ export default class Sider_Default extends React.PureComponent {
diff --git a/src/components/Layout/Sider/default.less b/src/components/Layout/Sider/default.less index 35b6478c..14e9bba6 100755 --- a/src/components/Layout/Sider/default.less +++ b/src/components/Layout/Sider/default.less @@ -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; } } } \ No newline at end of file diff --git a/src/pages/chats/Events.js b/src/pages/chats/Events.js new file mode 100644 index 00000000..1716d10e --- /dev/null +++ b/src/pages/chats/Events.js @@ -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" +} \ No newline at end of file diff --git a/src/pages/chats/chats/ChatContainer.js b/src/pages/chats/chats/ChatContainer.js new file mode 100644 index 00000000..2da94211 --- /dev/null +++ b/src/pages/chats/chats/ChatContainer.js @@ -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 ( +
+ +
+ { + activeChat !== null ? ( + +
+ + + { + this.sendMessage(activeChat.id, message) + } + } + sendTyping={ + (isTyping)=>{ + this.sendTyping(activeChat.id, isTyping) + } + } + /> + +
+ ): +
+

Choose a chat!

+
+ } +
+ +
+ ); + } +} diff --git a/src/pages/chats/chats/ChatHeading.js b/src/pages/chats/chats/ChatHeading.js new file mode 100644 index 00000000..dd71b21b --- /dev/null +++ b/src/pages/chats/chats/ChatHeading.js @@ -0,0 +1,18 @@ +import React from 'react'; + +export default function({name, numberOfUsers}) { + + return ( +
+
+
{name}
+
+
+ {numberOfUsers ? numberOfUsers : null} +
+
+ +
+ ); + +} diff --git a/src/pages/chats/chats/SideBar.js b/src/pages/chats/chats/SideBar.js new file mode 100644 index 00000000..cfa2db81 --- /dev/null +++ b/src/pages/chats/chats/SideBar.js @@ -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 ( + + ); + + } +} diff --git a/src/pages/chats/index.js b/src/pages/chats/index.js index 422e0865..0416c103 100644 --- a/src/pages/chats/index.js +++ b/src/pages/chats/index.js @@ -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( -
Chats
- ) + +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 ( +
+ { + !user ? +

initializes....

+ : + + } +
+ ); + } + } diff --git a/src/pages/chats/messages/MessageInput.js b/src/pages/chats/messages/MessageInput.js new file mode 100644 index 00000000..ce7d9e56 --- /dev/null +++ b/src/pages/chats/messages/MessageInput.js @@ -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 ( +
+
+ + { e.keyCode !== 13 && this.sendTyping() } } + onChange = { + ({target})=>{ + this.setState({message:target.value}) + } + } + /> + +
+ +
+ ); + } +} diff --git a/src/pages/chats/messages/Messages.js b/src/pages/chats/messages/Messages.js new file mode 100644 index 00000000..cc4d2ec5 --- /dev/null +++ b/src/pages/chats/messages/Messages.js @@ -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 ( +
+
+ { + messages.map((mes)=>{ + return ( +
+
{mes.time}
+
+
{mes.message}
+
{mes.sender}
+
+
+ + ) + }) + } + { + typingUsers.map((name)=>{ + return ( +
+ {`${name} is typing . . .`} +
+ ) + }) + } +
+ + +
+ ); + } +} diff --git a/src/themes/base/index.less b/src/themes/base/index.less index 67069d58..6b00b58b 100755 --- a/src/themes/base/index.less +++ b/src/themes/base/index.less @@ -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);