Rev 5617 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
/* eslint-disable react/prop-types */
import React, { useEffect, useRef, useState } from 'react'
import { ArrowLeft } from '@mui/icons-material'
import { useDispatch } from 'react-redux'
import { addNotification } from '../../redux/notification/notification.actions'
import { axios, scrollToBottom } from '../../utils'
import { fetchMessages, getMessagesDifferences } from '../../services/chat'
import QuestionAnswerRoundedIcon from '@mui/icons-material/QuestionAnswerRounded'
import SpeakerNotesOffRoundedIcon from '@mui/icons-material/SpeakerNotesOffRounded'
import EmptySection from '../../shared/empty-section/EmptySection'
import MessageBox from './MessageBox'
import MessageTemplate from './MessageTemplate'
import ConfirmModal from '../../shared/confirm-modal/ConfirmModal'
import IconButton from '@mui/material/IconButton'
import MoreVertIcon from '@mui/icons-material/MoreVert'
const DEFAULT_PAGES = { current: 1, last: 1 }
const Chatmail = ({
selectedConversation = null,
setConversation = () => null,
}) => {
const [oldMessages, setOldMessages] = useState([])
const [messages, setMessages] = useState([])
const [pages, setPages] = useState(DEFAULT_PAGES)
const [loading, setLoading] = useState(false)
const [displayOptions, setDisplayOptions] = useState(false)
const [isShowConfirm, setIsShowConfirm] = useState(false)
const lastMessage = useRef(null)
const messagesList = useRef(null)
const dispatch = useDispatch()
const getMoreMessages = async (url = '', page = pages.current) => {
try {
setLoading(true)
const response = await fetchMessages(url, page)
if (!response.success) {
const errorMessage = response.data
dispatch(
addNotification({ style: 'danger', msg: errorMessage.message })
)
return
}
if (response.pagination.current > 1) {
setOldMessages((prevOldMessages) => [
...prevOldMessages,
...response.data,
])
}
setPages((prevPages) => ({
...prevPages,
last: response.pagination.last,
}))
return
} catch (error) {
const errorMessage = new Error(error)
console.log('Request canceled', errorMessage)
} finally {
setLoading(false)
}
}
const hearBeat = async () => {
try {
setLoading(true)
const response = await fetchMessages(
selectedConversation.messages_link,
1
)
if (!response.success) {
const errorMessage = response.data
dispatch(
addNotification({ style: 'danger', msg: errorMessage.message })
)
return
}
const newMessages = getMessagesDifferences(messages, response.data)
if (newMessages.length) {
setMessages([...newMessages, ...messages])
scrollToBottom()
} else {
setMessages(response.data)
}
setPages((prevPages) => ({
...prevPages,
last: response.pagination.last,
}))
} catch (error) {
const errorMessage = new Error(error)
console.log('Request canceled', errorMessage)
} finally {
setLoading(false)
}
}
const handleSend = async (sendUrl = '', message = {}) => {
try {
const formData = new FormData()
Object.entries(message).forEach(([key, value]) =>
formData.append(key, value)
)
const { data: response } = await axios.post(sendUrl, formData)
setMessages((prev) => [response.data, ...prev])
} catch (error) {
const errorMessage = new Error(error)
dispatch(addNotification({ style: 'danger', msg: errorMessage.message }))
}
}
const loadMore = async () => {
setPages((prevPages) => ({ ...prevPages, current: prevPages.current + 1 }))
}
const toggleConfirmModal = () => {
setIsShowConfirm(!isShowConfirm)
}
const deleteConversation = () => {
axios.post(selectedConversation.delete_link).then(({ data: response }) => {
const { success, data } = response
if (!success) {
dispatch(addNotification({ style: 'danger', msg: data }))
return
}
dispatch(addNotification({ style: 'success', msg: data }))
setConversation(null)
})
}
useEffect(() => {
if (!loading && selectedConversation) setTimeout(() => hearBeat(), 3000)
}, [loading, selectedConversation])
useEffect(() => {
if (messages) setMessages([])
scrollToBottom(messagesList)
setPages(DEFAULT_PAGES)
}, [selectedConversation])
useEffect(() => {
if (selectedConversation)
getMoreMessages(selectedConversation?.messages_link, pages.current)
}, [pages.current])
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
loadMore()
}
})
if (lastMessage.current) {
observer.observe(lastMessage.current)
}
}, [messages])
if (!selectedConversation) {
return (
<EmptySection
message={LABELS.SELECT_CONVERSATION}
Icon={<QuestionAnswerRoundedIcon />}
/>
)
}
return (
<>
<div className="chat">
<span className="icon-hide" onClick={() => setConversation(null)}>
<ArrowLeft />
{LABELS.RETURN}
</span>
<div className="chat_header">
<a href={selectedConversation.profile}>
<h2 className="chat-header">{selectedConversation.name}</h2>
</a>
<div className="header-options">
<IconButton onClick={() => setDisplayOptions(!displayOptions)}>
<MoreVertIcon />
</IconButton>
<div className="position-relative">
<div className={`feed-options ${displayOptions ? 'active' : ''}`}>
<ul>
<li>
<button className="option-btn" onClick={toggleConfirmModal}>
<i className="fa fa-trash-o mr-1" />
Borrar
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
<div className="messages-line" ref={messagesList}>
{messages.length ? (
[...oldMessages, ...messages].map((element, index) => (
<MessageTemplate
key={index}
message={element}
date={element.date}
/>
))
) : (
<EmptySection
message={LABELS.NO_MESSAGE_CONVERSATION}
Icon={<SpeakerNotesOffRoundedIcon />}
/>
)}
{pages.current < pages.last && (
<hr ref={lastMessage} style={{ opacity: 0, margin: 0 }} />
)}
</div>
<MessageBox
onSend={handleSend}
sendUrl={selectedConversation.send_link}
/>
</div>
<ConfirmModal
show={isShowConfirm}
onClose={toggleConfirmModal}
onAccept={deleteConversation}
acceptLabel="Aceptar"
/>
</>
)
}
export default Chatmail