Jelajahi Sumber

new styles and start privat message reducer

serg1557733 1 tahun lalu
induk
melakukan
b5c9fc0284

+ 2 - 2
backend/app.js

@@ -333,8 +333,8 @@ const onUser = []
                 // }
            });
 
-        socket.on('privat', (data) => {
-            console.log(data)
+        socket.on('private message', (user) => {
+            console.log(user)
         
         })
 

+ 6 - 3
frontend/src/components/chatPage/ChatPage.jsx

@@ -4,7 +4,7 @@ import TextareaAutosize from '@mui/material/TextareaAutosize';
 import { MessageForm } from './messageForm/MessegaForm';
 import { UserInfo } from './userInfo/UserInfo';
 import { store } from '../../store';
-import { removeToken} from '../../reducers/userDataReducer'
+import { removeToken, isPrivatChat} from '../../reducers/userDataReducer'
 import { useDispatch, useSelector } from 'react-redux';
 import {getSocket} from'../../reducers/socketReducer';
 import { sendMessage, storeMessage, fileMessage } from '../../reducers/messageReducer';
@@ -17,6 +17,7 @@ import './chatPage.scss';
 import WebcamCapture from './service/webCam/WebcamCapture';
 import useSound from 'use-sound';
 import getNotif from '../../assets/sendSound.mp3'
+import { PrivateChat } from './privateChat/PrivateChat';
 
 export const ChatPage = () => {
 
@@ -30,6 +31,8 @@ export const ChatPage = () => {
     const editOldMessage = useSelector(state => state.messageReducer.editMessage)
     let showUserInfoBox = useSelector(state => state.messageReducer.showUserInfoBox)// || localStorage.getItem('showBox');
 
+    const isPrivatChat = useSelector(state => state.userDataReducer.isPrivatChat)
+
     const [message, setMessage] = useState({message: ''});
     const [isUserTyping, setUserTyping] = useState([]);
     const [isCamActiv, setisCamActiv] = useState(false);
@@ -138,8 +141,8 @@ export const ChatPage = () => {
                  </div> 
                  :
                  ""}
-                    <MessageForm/>
-
+                    {isPrivatChat?<PrivateChat/> : <MessageForm/>}
+                    
                     {isUserTyping.isTyping && (isUserTyping.userName !== user.userName)? <span> User {isUserTyping.userName} typing..</span> : ""}
 
                     <Box 

+ 0 - 2
frontend/src/components/chatPage/messageForm/MessegaForm.jsx

@@ -42,8 +42,6 @@ export const MessageForm = () => {
         } 
       }, [startMessages, messages, newMessages]);
            
-    console.log(usersOnline)
-
     useEffect(()=> {
         if(newMessages.length > 0 && newMessages[newMessages.length-1].userName !== user.userName){
            // play()                 

+ 141 - 0
frontend/src/components/chatPage/privateChat/PrivateChat.jsx

@@ -0,0 +1,141 @@
+import { Avatar, Box, Button} from '@mui/material';
+import { dateFormat } from '../utils/dateFormat';
+import { useSelector } from 'react-redux';   
+import { useRef, useEffect, useState} from 'react';
+import { scrollToBottom } from '../utils/scrollToBottom';
+import { useDispatch } from 'react-redux';
+import { editMessage } from '../../../reducers/messageReducer';
+import { MessageEditorMenu } from '../MessageEditorMenu.jsx';
+import imgBtn from '../../../assets/img/gg.png';
+import useSound from 'use-sound';
+import notifSound from '../../../assets/get.mp3'
+
+
+export const PrivateChat = () => {
+
+    const dispatch = useDispatch();
+    const socket = useSelector(state => state.getUserSocketReducer.socket)
+
+    const SERVER_URL =process.env.REACT_APP_SERVER_URL
+
+    const startMessages = useSelector(state => state.getUserSocketReducer.startMessages)
+    const user = useSelector(state => state.getUserSocketReducer.socketUserData)
+    const usersOnline = useSelector(state => state.getUserSocketReducer.usersOnline)
+    const userNamesOnlineSet =  new Set(usersOnline.map( i => i.userName))
+    const storeMessageId = useSelector(state => state.messageReducer.messageId)
+    const newMessages = useSelector(state => state.getUserSocketReducer.newMessages)
+
+    let endMessages = useRef(null);
+    const [isEditing, setIsEditing] = useState(false)   
+    const [isEditiedMessage, setIsEditiedMessage] = useState(false) //need to type in the bottom of message after message was edited
+
+    const regYoutube = /http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?‌​[\w\?‌​=]*)?/; //for youtube video
+    const messages = startMessages.concat(newMessages)  
+
+    const [play] = useSound(notifSound);
+
+    useEffect(() => {
+        if (!isEditing) {
+            scrollToBottom((endMessages)) 
+        } 
+      }, [startMessages, messages, newMessages]);
+           
+    useEffect(()=> {
+        if(newMessages.length > 0 && newMessages[newMessages.length-1].userName !== user.userName){
+           // play()                 
+        }
+    }, [newMessages])
+
+    return (             
+            <Box className='messageBox'>  
+                {
+                messages.map((item, i) =>
+                    <div key={i + 1} className={ 
+                        (item.userName === user.userName)? 'message myMessage' :'message'}
+                        onClick = {(e) => {
+                            console.log(e.target)
+                            if(e.target.closest("div").className.includes('myMessage') && (item.userName === user.userName) && (item.text === e.target.textContent)){
+                                e.currentTarget.className += ' editMessage'  
+                                dispatch(editMessage({socket, editMessage: e.target.textContent, messageId: item._id}))  
+                                setIsEditing(true)
+                                }
+                        }}
+                        > 
+                        {storeMessageId === item._id ? <MessageEditorMenu />: ""} 
+                        <span
+                            style={{'alignItems': 'center',
+                                    marginLeft: 5, 
+                                    fontStyle: 'italic', 
+                                    fontWeight: 800
+                                }}
+
+                        > {item.userName}</span>
+                        <div 
+                            key={i}
+                        
+                            className={ 
+                                (item.userName === user.userName)? 'message myMessage' :'message'}>
+                           
+                           { 
+                           item.text.match(regYoutube) ?
+                           <iframe 
+                                width="280" 
+                                height="160" 
+                                style={{'maxWidth': "90%"}}
+                                src={`https://www.youtube.com/embed/`+ (item.text.match(regYoutube)[1])}
+                                title="YouTube video player" 
+                                allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" 
+                                allowFullScreen> 
+                                
+                            </iframe>
+                            :
+                            (item.file && item.fileType && item.fileType.split('/')[0] !== 'image') ? 
+
+                            <div style={{'display': 'flex', 'alignItems': 'center'}} >
+
+                                <a href={SERVER_URL + '/' +item.file} download> 
+                                    <Button
+                                        variant="contained" 
+                                        component="label"
+                                        sx = {{
+                                            minWidth: 'auto',
+                                            minHeight: '25px',
+                                            backgroundImage:'url(' + imgBtn + ')' ,
+                                            backgroundPosition: 'center', 
+                                            backgroundRepeat: "no-repeat", 
+                                            backgroundSize: '15px 20px',
+                                            backgroundColor: '#d3d3d3'
+
+                                        }}  
+                                    >
+                                    </Button>  
+                                </a>
+                                <p style={{'marginLeft': '15px'}}  >{item.text}</p>  
+                            </div>
+                        : 
+                            <p>{item.text}</p>
+                          
+                           }
+
+                        { 
+                            (item.file && item.fileType && item.fileType.split('/')[0] == 'image' ) //need to fix for other type files
+                            ? 
+                                <img width={'auto'} style={{'maxWidth': "90%"}} src={ SERVER_URL + '/' + item.file} alt={'error load image'}/>
+                            :
+                            ''
+                        }
+
+                        </div>
+                        {isEditiedMessage && <i>Edited</i>}
+                        <div className={ 
+                                (item.userName === user.userName)? 'myDate' :'date'}>
+                                {dateFormat(item).time}
+                        </div>
+                    </div>
+                )}
+
+                <div ref={endMessages}></div>
+
+            </Box>
+    )
+} 

+ 11 - 3
frontend/src/components/chatPage/userInfo/UserInfo.jsx

@@ -4,7 +4,7 @@ import { banUser } from '../service/banUser';
 import { muteUser } from '../service/muteUser';
 import './userInfo.scss';
 import { useDispatch } from 'react-redux';
-import { getUserAvatar } from '../../../reducers/userDataReducer';
+import { getUserAvatar, privateMessage } from '../../../reducers/userDataReducer';
 import { useState, useEffect } from 'react';
 import { store } from '../../../store';
 import { getSocket } from '../../../reducers/socketReducer';
@@ -43,6 +43,9 @@ export const UserInfo = () => {
     const socket = useSelector(state => state.getUserSocketReducer.socket)
     const isTabletorMobile = (window.screen.width < 730);
     const storeUserAvatar = useSelector(state => state.userDataReducer.avatar)
+    const isPrivatChat = useSelector(state => state.userDataReducer.isPrivatChat)
+    const chatId = useSelector(state => state.userDataReducer.chatId)
+
 
 
 
@@ -158,8 +161,13 @@ export const UserInfo = () => {
                      (user.userName !== item.userName) &&
                       <div 
                             key={i}
-                            className='online'                        
-                            onClick={() => console.log(item)}
+                            className={isPrivatChat&&(chatId==user._id)? 'online active' :'online' }                       
+                            onClick={() => {
+                                console.log(item.userName)
+                                store.dispatch(privateMessage(user._id))
+                                socket.emit('private message', user )
+                            }
+                            }
                             >  
                             
                                 <div style={{color: item.color}}>

+ 4 - 0
frontend/src/components/chatPage/userInfo/userInfo.scss

@@ -4,4 +4,8 @@
     height: 100px;
     font-size: 14;
     margin: 20px auto;
+}
+
+.active {
+    background-color:rgb(12, 40, 77);
 }

+ 8 - 1
frontend/src/reducers/userDataReducer.js

@@ -13,6 +13,8 @@ const initialState = {
     socket: null, 
     responseMessage: '',
     showUserInfoBox: false,
+    isPrivatChat: false,
+    chatId: '',
     avatar: ''
 }
 const SERVER_URL =  process.env.REACT_APP_SERVER_URL
@@ -59,6 +61,10 @@ const getUserDataSlice = createSlice({
     name: 'userData',
     initialState,
     reducers: {
+        privateMessage: (state, action)=> {
+            state.isPrivatChat = true;
+            state.chatId = action.payload.chatId
+        },
         setUserName: (state, action) => {state.userName = action.payload.userName},
         setUserPassword: (state, action) => {state.password = action.payload.password},
             
@@ -111,5 +117,6 @@ export const {
     setUserPassword,
     removeToken,
     deleteResponseMessage,
-    showUserInfoBox
+    showUserInfoBox,
+    privateMessage
 } = actions;