unknown 2 rokov pred
rodič
commit
574114af71

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
.eslintcache


+ 11 - 0
package-lock.json

@@ -40,6 +40,7 @@
         "react-file-viewer": "^1.2.1",
         "react-js-pagination": "^3.0.3",
         "react-loader-spinner": "^4.0.0",
+        "react-media-recorder": "^1.6.3",
         "react-query": "^3.24.3",
         "react-redux": "^7.2.2",
         "react-responsive-carousel": "^3.2.23",
@@ -18111,6 +18112,11 @@
         "react-dom": "*"
       }
     },
+    "node_modules/react-media-recorder": {
+      "version": "1.6.3",
+      "resolved": "https://registry.npmjs.org/react-media-recorder/-/react-media-recorder-1.6.3.tgz",
+      "integrity": "sha512-uJ5lys9JNzE77cLXZ0EOg9jxAqQb6BpntHHRpC1nHaVKA0ygbGLvBVXU95xms+VnS9mp8pW21oM9uxAjBylTtg=="
+    },
     "node_modules/react-query": {
       "version": "3.24.3",
       "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.24.3.tgz",
@@ -38536,6 +38542,11 @@
         "prop-types": "^15.7.2"
       }
     },
+    "react-media-recorder": {
+      "version": "1.6.3",
+      "resolved": "https://registry.npmjs.org/react-media-recorder/-/react-media-recorder-1.6.3.tgz",
+      "integrity": "sha512-uJ5lys9JNzE77cLXZ0EOg9jxAqQb6BpntHHRpC1nHaVKA0ygbGLvBVXU95xms+VnS9mp8pW21oM9uxAjBylTtg=="
+    },
     "react-query": {
       "version": "3.24.3",
       "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.24.3.tgz",

+ 1 - 0
package.json

@@ -36,6 +36,7 @@
     "react-file-viewer": "^1.2.1",
     "react-js-pagination": "^3.0.3",
     "react-loader-spinner": "^4.0.0",
+    "react-media-recorder": "^1.6.3",
     "react-query": "^3.24.3",
     "react-redux": "^7.2.2",
     "react-responsive-carousel": "^3.2.23",

+ 57 - 18
src/components/HomePage/RightBar/ChatBar/SendMessage/index.tsx

@@ -6,6 +6,7 @@ import SentimentSatisfiedAltIcon from '@mui/icons-material/SentimentSatisfiedAlt
 import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
 import Avatar from '@mui/material/Avatar';
 import CloseIcon from '@mui/icons-material/Close';
+import { useReactMediaRecorder } from "react-media-recorder";
 import { useState } from "react";
 import { useSelector } from "react-redux";
 
@@ -20,7 +21,6 @@ import { getIsOpen } from '../../../../../redux/control/selector'
 import { playNotification } from "../../../../../helpers";
 import { typingChat } from "../../../../../api-data";
 
-
 const useStyles = makeStyles({   
     container: {
         display: "flex",
@@ -84,7 +84,7 @@ const useStyles = makeStyles({
             color: 'rgb(82, 82, 82)',
             fontWeight: 600
         }
-    },  
+    },    
     attachIcon: {
         transform:'rotate(30deg)',  
     },
@@ -162,14 +162,39 @@ const SendMessage = ({isArrow,handleScrollTo}:ISendMessage) => {
     const [file, setFile] = useState<any>(null)
     const [isOpenMenu, setIsOpenMenu] = useState<boolean>(false)
     const [isOpenEmoji, setIsOpenEmoji] = useState<boolean>(false)
+    const [isRecording, setIsRecording] = useState<boolean>(false)
     const [type, setType] = useState<string>('')
+    const { status, startRecording, stopRecording, mediaBlobUrl,clearBlobUrl } = useReactMediaRecorder({ audio: true });
     const sentMessage = async () => {
-        setValue('')
         setFile(null)
+        setIsRecording(false)
+        setValue('')
+        setType('')
         isOpenMenu&&setIsOpenMenu(false)
         isOpenEmoji && setIsOpenEmoji(false)
         if (value) sentMessageById(companionId, value)
-        if (file && file.type&&type) {
+        if (mediaBlobUrl && type) {
+            if (type === 'recording') {
+            const audio = new XMLHttpRequest();
+            audio.open('GET', mediaBlobUrl, true);
+              audio.responseType = 'blob';
+              audio.onload = () => {
+                  if (audio.status === 200) {
+                      const name = `audioMessage${new Date().getSeconds()}.mp3`
+                      const blob = audio.response
+                      const file = new File([blob], name, {
+                        type: 'audio/mpeg'
+                      })
+                    const formData: any = new FormData()
+                    formData.append("audio", file)
+                  sentAudioMessageById(companionId, formData)
+                  clearBlobUrl()
+                }
+              }
+            audio.send();
+           } 
+        }
+        if (file && type) {
             if (file.type.includes('image') && type === 'content') {
               const formData: any = new FormData()
               formData.append("image", file);
@@ -179,7 +204,7 @@ const SendMessage = ({isArrow,handleScrollTo}:ISendMessage) => {
               const formData: any = new FormData()
               formData.append("audio", file);
               sentAudioMessageById(companionId, formData)
-            }
+            }           
             if (file.type.includes('video') && type === 'content') {
               const formData: any = new FormData()
               formData.append("video", file);
@@ -209,16 +234,27 @@ const SendMessage = ({isArrow,handleScrollTo}:ISendMessage) => {
     const handleCloseEmoji = (e: any) => {
         if (e.target.id === 'overlay'&&isOpenEmoji) setIsOpenEmoji(false) 
     }
+    const handleRecording = () => {
+        if (isRecording) {
+            stopRecording()
+        } else {
+            startRecording()
+            setType('recording')
+            setIsRecording(true)
+        }
+    }
     const handleClearMessage = () => {
-        file && setFile(null)
+        file&&setFile(null)
         value&&setValue('')
+        type&&setType('')
     }
     
     return (
         <div className={classes.container} style={{borderTop:isArrow?'solid 1px #ffffff':'none'}} >            
             <div onKeyPress={handleKeyPres} className={classes.inputContainer}>
                 <CloseIcon onClick={handleClearMessage} fontSize="small" className={classes.iconCancel}
-                    sx={{backgroundColor:'#ffffff',width:36,height:36,color:'#949393',display:file || value?'inline-block':'none'}}/>
+                    sx={{backgroundColor: '#ffffff', width: 36, height: 36, color: '#949393',
+                    display: file || value ? 'inline-block' : 'none'}} />
                 <SentimentSatisfiedAltIcon onClick={handleOpenEmoji}
                     fontSize='medium' sx={{
                         color: isOpenEmoji ? 'rgb(41, 139, 231)' : '#6b6b6b', cursor: 'pointer',
@@ -232,7 +268,8 @@ const SendMessage = ({isArrow,handleScrollTo}:ISendMessage) => {
                 </div>
                 <textarea disabled={file ? true : false} value={value} onBlur={handleBlurTextarea}
                     onFocus={handleFocusTextarea} onChange={handleTextarea} className={classes.textarea}
-                    placeholder={file ? 'The File is ready to send' : 'Message'} rows={1}>
+                    placeholder={file ? 'The File is ready to send' : status === 'idle' ? 'Message' :
+                    `${status === 'recording'?'Recording':'Audio message Recorded'}`} rows={1}>
                </textarea>
                 <AttachFileIcon onClick={handleOpenFileMenu} className={classes.attachIcon}
                     fontSize='medium' sx={{
@@ -245,22 +282,24 @@ const SendMessage = ({isArrow,handleScrollTo}:ISendMessage) => {
                       <FilesMenu setFile={setFile} setValue={setValue} setIsOpenMenu={setIsOpenMenu} setType={setType}/>
                     </div>
                 </div>
-                <Avatar onClick={handleScrollTo} className={classes.avatarArrow} sx={{
-                  backgroundColor: '#ffffff',
-                   width: 56, height: 56 ,color: '#6b6b6b',display:isArrow?'flex':'none'}}>
+                <Avatar onClick={handleScrollTo} className={classes.avatarArrow}
+                    sx={{backgroundColor: '#ffffff', width: 56, height: 56,
+                    color: '#6b6b6b', display: isArrow ? 'flex' : 'none'}}>
                   <ArrowDownwardIcon fontSize="medium" />
                 </Avatar>                 
             </div>  
-            {value || file ?
+            {value || file || mediaBlobUrl ?
              <Avatar onClick={sentMessage} className={classes.avatar} sx={{
-               backgroundColor: '#ffffff',
-               width: 56, height: 56 ,color: 'rgb(41, 139, 231)'}}>
+                backgroundColor: '#ffffff', width: 56, height: 56, color: 'rgb(41, 139, 231)',
+                }}>
                   <SendIcon fontSize="medium" />
             </Avatar> :
-             <Avatar className={classes.avatar} sx={{
-               backgroundColor: '#ffffff',
-                    width: 56, height: 56, color: '#6b6b6b'}}>                   
-                    <MicNoneIcon fontSize="medium" />                    
+                <Avatar onClick={handleRecording} className={!isRecording ? classes.avatar : undefined}
+                    sx={{backgroundColor: isRecording ? 'rgb(41, 139, 231)' : '#ffffff',
+                    color: isRecording ? '#ffffff' : '#6b6b6b', width: 56, height: 56}}
+                    style={{animation: isRecording ? 'ripple 1.5s infinite ease-in-out' : 'none',
+                    border: isRecording?'solid 5px #ffffff':'none'}}>
+                <MicNoneIcon fontSize="medium" />                    
             </Avatar>}
         </div>            
     )