4 Комити 5a2bf70186 ... cfc0ff23d6

Аутор SHA1 Порука Датум
  serg1557733 cfc0ff23d6 add webcam photo with sending and using photo for avatar пре 1 година
  serg1557733 bab3bc80f2 add webcam component add buttons пре 1 година
  serg1557733 0f9da480e4 add webcam component start working on photo пре 1 година
  serg1557733 49c72b27a8 fix image sending пре 1 година

+ 9 - 4
backend/app.js

@@ -150,7 +150,8 @@ app.post('/files', async (req, res) =>  {
             userName: user.userName,
             createDate: Date.now(),
             user: oneUser.id, //add link to other collection by id
-            file: file.name
+            file: file.name,
+            fileType: file.mimetype
         });
 
         try {
@@ -169,13 +170,17 @@ app.post('/files', async (req, res) =>  {
 
    }}     
     else {
+            if (files.name == 'blob') {
+                files.name = Uuid.v4() + '.jpeg'
+            }
             files.mv(STATIC_PATH + '\/' + files.name);      //for one file       
             const message = new Message({
                 text: files.name,
                 userName: user.userName,
                 createDate: Date.now(),
                 user: oneUser.id, //add link to other collection by id
-                file: files.name
+                file: files.name,
+                fileType: files.mimetype
             });
     
             try {
@@ -189,8 +194,8 @@ app.post('/files', async (req, res) =>  {
             catch (error) {
                 console.log('Message save to db error', error);   
             }
-            const newMessages = await message.populate( {path:'user'})  
-            io.emit('newmessage', newMessages); 
+           const newMessages = await message.populate( {path:'user'})  
+           io.emit('newmessage', newMessages); 
     } 
 
     return res.json({ message:'File was uploud succesfully...'})

+ 2 - 1
backend/db/models/Message.js

@@ -5,7 +5,8 @@ const Message = new Schema({
     userName : {type: String, required: true},
     createDate: {type: Date, required: true},
     user: { type: Schema.Types.ObjectId, ref: 'User' },//not using 
-    file: {type: String} 
+    file: {type: String} ,
+    fileType: {type: String} 
 
 })
 

+ 39 - 4
frontend/src/components/chatPage/ChatPage.jsx

@@ -11,8 +11,10 @@ import { sendMessage, storeMessage, fileMessage } from '../../reducers/messageRe
 import { editMessage } from '../../reducers/messageReducer';
 import { SwitchButton } from './SwitchButton';
 import { MessageEditorMenu } from './MessageEditorMenu.jsx';
-import imgBtn from '../../assets/img/gg.png'
+import imgBtn from '../../assets/img/gg.png';
+import imgBtnPhoto from '../../assets/img/photo.png'
 import './chatPage.scss';
+import WebcamCapture from './service/webCam/WebcamCapture';
 
 
 export const ChatPage = () => {
@@ -29,9 +31,16 @@ export const ChatPage = () => {
 
     const [message, setMessage] = useState({message: ''});
     const [isUserTyping, setUserTyping] = useState([]);
+    const [isCamActiv, setisCamActiv] = useState(false);
     
     const isTabletorMobile = (window.screen.width < 730);
 
+
+    const webcamEventHandler = () => {
+        setisCamActiv(!isCamActiv)
+
+    }
+
     useEffect(() => {
         if(socket) {
             socket.on('writing', (data) => { 
@@ -61,7 +70,19 @@ export const ChatPage = () => {
                 { isTabletorMobile ? <SwitchButton/> : null}
                 
                 <Box className ={isTabletorMobile ? 'rootMessageFormMobile':'rootMessageForm'} >
-                    
+                {isCamActiv ? 
+                <div>  
+                    <Button
+                        variant="contained" 
+                        component="label"
+                        onClick = {() => webcamEventHandler()}
+                    >
+                        close camera
+                    </Button> 
+                    <WebcamCapture />   
+                 </div> 
+                 :
+                 ""}
                     <MessageForm/>
 
                     {isUserTyping.isTyping && (isUserTyping.userName !== user.userName)? <span> User {isUserTyping.userName} typing..</span> : ""}
@@ -84,7 +105,6 @@ export const ChatPage = () => {
                             margin: '20px 5px'}
                            
                         }>
-
                         <Button
                             variant="contained" 
                             component="label"
@@ -108,7 +128,22 @@ export const ChatPage = () => {
                         />
 
                        
-                        </Button>            
+                        </Button>    
+                        <Button
+                            variant="contained" 
+                            component="label"
+                            sx = {{
+                                minWidth: 'auto',
+                                backgroundImage:'url(' + imgBtnPhoto + ')' ,
+                                backgroundPosition: 'center', 
+                                backgroundRepeat: "no-repeat", 
+                                backgroundSize: '20px 20px'
+
+                            }}
+
+                            onClick = {() => webcamEventHandler()}
+                        >
+                        </Button>          
 
                         <TextareaAutosize
                             id="outlined-basic" 

+ 16 - 18
frontend/src/components/chatPage/messageForm/MessegaForm.jsx

@@ -29,7 +29,6 @@ export const MessageForm = () => {
 
     useEffect(() => {
         scrollToBottom(endMessages)
-        console.log('useEffect', endMessages)
       }, [startMessages]);
                   
     return (             
@@ -91,47 +90,46 @@ export const MessageForm = () => {
                                 
                             </iframe>
                             :
-                            <p>{item.text}</p>  
-                           }
-
-                           {
-                            (item.file && item.file.split('.')[1] !== 'jpeg') ? 
+                           
+                            (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: '40px',
+                                            minHeight: '25px',
                                             backgroundImage:'url(' + imgBtn + ')' ,
                                             backgroundPosition: 'center', 
                                             backgroundRepeat: "no-repeat", 
-                                            backgroundSize: '20px 40px'
-
-                                        }}
+                                            backgroundSize: '15px 20px',
+                                            backgroundColor: '#d3d3d3'
 
-                                    
-                                        
+                                        }}  
                                     >
                                     </Button>  
                                 </a>
+                                <p style={{'marginLeft': '15px'}}  >{item.text}</p>  
+                            </div>
                         : 
-                            ''                            
-                        }
+                                                       
+                            <p>{item.text}</p>  
+                           }
 
-                        {
-                            (item.file && item.file.split('.')[1] == 'jpeg' ) //need to fix for other type files
+                        { 
+                            (item.file && item.fileType && item.fileType.split('/')[0] == 'image' ) //need to fix for other type files
                             ? 
+
                                  <img width={150} height={150} src={ SERVER_URL + item.file} alt={'error load image'}/>
                             :
                             ''
-
                         }
 
                         </div>
 
-
                         <div className={ 
                                 (item.userName === user.userName)? 'myDate' :'date'}>
                                 {dateFormat(item).time}

+ 89 - 0
frontend/src/components/chatPage/service/webCam/WebcamCapture.jsx

@@ -0,0 +1,89 @@
+import {useRef, useState, useCallback} from 'react';
+import Webcam from "react-webcam";
+import {Button} from '@mui/material';
+import { fileMessage } from '../../../../reducers/messageReducer';
+import { useDispatch } from 'react-redux';
+import { getUserAvatar } from '../../../../reducers/userDataReducer';
+
+
+const WebcamCapture = () => {
+
+    const dispatch = useDispatch();
+
+    const webcamRef = useRef(null);
+    const [imgSrc, setImgSrc] = useState(null);
+
+    const sendPhotoToChat = async (imageStream) => {
+        const blob = await fetch(imageStream).then((res) => res.blob());
+        dispatch(fileMessage(blob)) 
+    }
+
+    const savePhotoToAvatar = async (imageStream) => {
+        const blob = await fetch(imageStream).then((res) => res.blob());
+        dispatch(getUserAvatar(blob)) 
+    }
+
+    const capture = useCallback(async () => {
+      const imageSrc = webcamRef.current.getScreenshot();
+      setImgSrc(imageSrc);
+    }, [webcamRef, setImgSrc]);
+  
+    return (
+      <div style={{
+        'maxHeight': '350px',
+        'maxWidth': '350px',
+        'position': 'absolute',
+        'top': '10%', 
+        "left": '10%',
+        'zIndex': 9999,
+        
+    }}>
+        <Webcam
+          audio={false}
+          ref={webcamRef}
+          screenshotFormat="image/jpeg"
+          style={{
+            'maxHeight': '350px',
+            'maxWidth': '350px'
+        }}
+        />
+        <Button
+                onClick={capture}
+                variant="contained" 
+                component="label" 
+          >
+            New photo 
+          </Button>          {imgSrc && (
+          <>        
+          <Button
+              variant="contained" 
+              component="label"
+              onClick={() => sendPhotoToChat(imgSrc)}
+            
+          >
+            Send
+          </Button>  
+          <Button
+              variant="contained" 
+              component="label" 
+              onClick={() => savePhotoToAvatar(imgSrc)}
+
+          >
+            Save avatar
+          </Button>
+          <img
+            src={imgSrc}
+            style={{
+             'border':'4px solid blue',
+             'borderRadius': '10px'
+          }}
+            
+          />
+
+          </>
+        )}
+      </div>
+    );
+  };
+
+  export default WebcamCapture;

+ 5 - 2
frontend/src/reducers/messageReducer.js

@@ -22,7 +22,6 @@ export const sendMessageToSocket = (state, data) => {
             } 
     };
 
-
 export const editMessageToSocket = (state, data) => {
         if (state.message && state.message.length < 200) {    
            data.socket.emit('editmessage', {...data.user, message: state.message}); //add backend functional later find by id and edit   
@@ -35,8 +34,12 @@ export const fileMessage = createAsyncThunk(
         const token = localStorage.getItem('token')
         try {
             const formData = new FormData();
-            for (let i = 0; i < files.length; i++) {
+            if(files.length) {
+                 for (let i = 0; i < files.length; i++) {
                 formData.append('files', files[i])
+                }
+            } else {
+                formData.append('files', files)
             }
             formData.append('token', token)
             const response = await axios.post(POST_FILES_URL, formData,

+ 2 - 1
frontend/src/reducers/socketReducer.js

@@ -4,6 +4,7 @@ import { store } from '../store';
 import { removeToken } from './userDataReducer';
 
 
+
 const initialState = {
     socketStatus: 'idle',
     socket: null,
@@ -15,6 +16,7 @@ const initialState = {
     usersWriting: []
 }
 
+
 const SOCKET_URL =  process.env.REACT_APP_SERVER_URL || 'http://localhost:5000'; 
 
 const connectToSocket = (event) => {
@@ -42,7 +44,6 @@ const connectToSocket = (event) => {
                                 })
                             .on('newmessage', (data) => {
                                 store.dispatch(addNewMessage(data))
-                                console.log(data)
                                 })
                             .on('ban', (data) => {
                                 store.dispatch(removeToken());