Rev 6345 | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
import React, { useEffect, useRef, useState } from 'react'import { axios, scrollToBottom } from '../../../utils'import { addNotification } from '../../../redux/notification/notification.actions'import { useDispatch } from 'react-redux'import SendIcon from '@mui/icons-material/Send'import IconButton from '@mui/material/IconButton'import MoreVertIcon from '@mui/icons-material/MoreVert'import AttachFileIcon from '@mui/icons-material/AttachFile'import InsertEmoticonIcon from '@mui/icons-material/InsertEmoticon'import ArrowBackIcon from '@mui/icons-material/ArrowBack'// Componentsimport Message from '../../../components/chat/Message'import Emojione from '../emojione/Emojione'import { ConferenceModal } from '../../../chat/chat/personal-chat/PersonalChat'import SendFileModal from '../../../chat/chat/personal-chat/send-file-modal/SendFileModal'const CHAT_TABS = {CHAT: 'CHAT',DEFAULT: 'DEFAULT',GROUP_MEMBERS: 'GROUP_MEMBERS',ADD_GROUP_MEMBER: 'ADD_GROUP_MEMBER',}const Chat = ({ entity, timezones, changeTab }) => {const {url_get_all_messages,url_mark_received,not_received_messages,not_seen_messages,url_zoom,url_send,url_upload,url_mark_seen,url_close,url_add_user_to_group, // Group urlurl_delete, // Group urlurl_get_contact_group_list, // Group urlurl_leave, // Group urlname,profile,type,} = entityconst [oldMessages, setOldMessages] = useState([])const [newMessages, setNewMessages] = useState([])const [currentPage, setCurrentPage] = useState(1)const [pages, setPages] = useState(1)const [showEmojione, setShowEmojione] = useState(false)const [isShowFileModal, setIsShowFileModal] = useState(false)const [isShowConferenceModal, setisShowConferenceModal] = useState(false)const [loading, setLoading] = useState(false)const [isSending, setIsSending] = useState(false)const [isGetting, setIsGetting] = useState(false)const dispatch = useDispatch()const scrollRef = useRef(null)const inputTextEl = useRef(null)// Messages gettersconst getMessages = async () => {setLoading(true)axios.get(url_get_all_messages).then(({ data: response }) => {const { data, success } = responseif (!success) {return}const messageResponse = [...data.items].reverse()const updatedMessages = messageResponse.reduce((acum, updatedMessage) => {if (newMessages.findIndex((message) => message.id === updatedMessage.id) === -1) {acum = [...acum, updatedMessage]}return acum},[])if (updatedMessages.length > 0) {setNewMessages((prevMessages) => [...prevMessages,...updatedMessages,])setPages(data.pages)scrollRef.current.scrollBy(0, 200)}}).finally(() => setLoading(false))}const loadOldMessages = () => {setIsGetting(true)axios.get(`${url_get_all_messages}?page=${currentPage}`).then(({ data: response }) => {const { data, success } = responseif (success && data.page > 1) {setOldMessages([...data.items.slice().reverse(), ...oldMessages])scrollRef.current.scrollBy(0, 200)}}).finally(() => setIsGetting(false))}// Sender functionsconst onHandleSubmit = (e) => {e.preventDefault()const formData = new FormData()// eslint-disable-next-line no-undefformData.append('message', emojione.toShort(inputTextEl.current.value))inputTextEl.current.value = ''axios.post(url_send, formData).then(({ data }) => {if (!data.success) {setShowEmojione(false)dispatch(addNotification({style: 'danger',msg:typeof data.data === 'string'? data.data: 'Ha ocurrido un error',}))return}setShowEmojione(false)scrollToBottom(scrollRef)})}const sendFile = (file) => {setIsSending(true)const formData = new FormData()formData.append('file', file)axios.post(url_upload, formData).then(({ data: response }) => {const { success, data } = responseif (!success) {const errorMessage =typeof data === 'string' ? data : 'Ha ocurrido un error'dispatch(addNotification({ style: 'success', msg: errorMessage }))return}toggleFileModal()scrollToBottom(scrollRef)}).finally(() => setIsSending(false))}const handleKeyDown = (e) => {if (e.key !== 'Enter') return false}// Modals handlersconst toggleFileModal = () => {setIsShowFileModal(!isShowFileModal)}const toggleEmojione = () => {setShowEmojione(!showEmojione)}const toggleConferenceModal = () => {setisShowConferenceModal(!isShowConferenceModal)}// On select emojiconst onClickEmoji = (event) => {const shortname = event.currentTarget.dataset.shortnameconst currentText = inputTextEl.current.valueconst cursorPosition = inputTextEl.current.selectionStartconst textBehind = currentText.substring(0, cursorPosition)const textForward = currentText.substring(cursorPosition)// eslint-disable-next-line no-undefconst unicode = emojione.shortnameToUnicode(shortname)inputTextEl.current.value = `${textBehind}${unicode}${textForward}`inputTextEl.current.focus()inputTextEl.current.setSelectionRange(cursorPosition + shortname.length,cursorPosition + shortname.length)}// On interception handlerconst onIntersection = (entities) => {const target = entities[0]if (target.isIntersecting && currentPage < pages) {setIsGetting(true)setCurrentPage((prevState) => prevState + 1)}}const deleteGroup = async (url) => {setLoading(true)axios.post(url).then(({ data: response }) => {const { data, success } = responseif (!success) {const errorMessage =typeof data.data === 'string' ? data.data : 'Ha ocurrido un error'dispatch(addNotification({ style: 'danger', msg: errorMessage }))return}changeTab(CHAT_TABS.DEFAULT)}).finally(() => setLoading(false))}const options = [{url: url_zoom,label: 'Crear Conferencia',action: toggleConferenceModal,},]const groupOptions = [{url: url_zoom,label: 'Crear Conferencia',action: toggleConferenceModal,},{url: url_get_contact_group_list,label: 'Integrantes',action: () => changeTab(CHAT_TABS.GROUP_MEMBERS),},{url: url_add_user_to_group,label: 'Agregar Contactos',action: () => changeTab(CHAT_TABS.ADD_GROUP_MEMBER),},{url: url_delete,label: 'Eliminar Grupo',action: () => deleteGroup(url_delete),},{url: url_leave,label: 'Dejar Grupo',action: () => deleteGroup(url_leave),},]useEffect(() => {let getInterval = nullif (loading) returngetInterval = setTimeout(() => getMessages(), 2000)return () => {clearTimeout(getInterval)}}, [loading])useEffect(() => {loadOldMessages()}, [currentPage])useEffect(() => {if (not_seen_messages) axios.post(url_mark_seen)if (not_received_messages) axios.post(url_mark_received)return () => {axios.post(url_close)}}, [])useEffect(() => {setNewMessages([])setOldMessages([])setPages(1)setCurrentPage(1)}, [entity])return (<><div className="chat"><Chat.Headername={name}profile={profile}options={type === 'group' ? groupOptions : options}changeTab={() => changeTab(CHAT_TABS.DEFAULT)}/>{![...newMessages, ...oldMessages].length ? (<div className="message-select-conversation"><div className="msgs-select-container"><i className="fas fa-inbox icon" /><h3>No hay mensajes en esta conversación</h3></div></div>) : (<Chat.ListisLastPage={currentPage >= pages}messages={[...oldMessages, ...newMessages]}onIntersection={onIntersection}scrollRef={scrollRef}isLoading={isGetting}/>)}<div className="chat__input-container"><form onSubmit={onHandleSubmit}>{showEmojione && <Emojione onClickEmoji={onClickEmoji} />}<buttontype="button"className="icon_btn"onClick={toggleFileModal}><AttachFileIcon /></button><button type="button" className="icon_btn" onClick={toggleEmojione}><InsertEmoticonIcon /></button><inputtype="text"className="chatInput"placeholder="Escribe un mensaje"onKeyDown={handleKeyDown}ref={inputTextEl}/><button type="submit" className="send_btn"><SendIcon /></button></form></div><SendFileModalisShow={isShowFileModal}onHide={toggleFileModal}onComplete={sendFile}loading={isSending}/><ConferenceModalshow={isShowConferenceModal}zoomUrl={url_zoom}timezones={timezones}onCreate={toggleConferenceModal}/></div></>)}const Header = ({ name, profile, options, changeTab }) => {return (<><div className="chat_header"><IconButton onClick={changeTab}><ArrowBackIcon /></IconButton><a href={profile}><h2>{name}</h2></a><Header.Options options={options} /></div></>)}const List = ({messages,onIntersection,isLastPage,scrollRef,isLoading,}) => {const loadMoreEl = useRef()useEffect(() => {const observer = new IntersectionObserver(onIntersection)if (loadMoreEl.current) {observer.observe(loadMoreEl.current)}return () => {observer.disconnect()}}, [messages])return (<div className="messages_container" ref={scrollRef}><div className="message_wrapper">{!isLastPage && !isLoading && <p ref={loadMoreEl}>Cargando...</p>}{messages.map((message) => (<Message message={message} key={message.id} />))}</div></div>)}const Options = ({ options }) => {const [isShowMenu, setIsShowMenu] = useState(false)const toggleOptions = () => {setIsShowMenu(!isShowMenu)}return (<div className="header-options"><IconButton onClick={toggleOptions}><MoreVertIcon /></IconButton><div className="position-relative"><div className={`feed-options ${isShowMenu ? 'active' : ''}`}><ul>{options.map((option, index) => {if (!option.url) {return null}return (<li key={index}><buttonclassName="btn option-btn"onClick={() => {option.action()toggleOptions()}}>{option.label}</button></li>)})}</ul></div></div></div>)}Chat.Header = HeaderChat.List = ListHeader.Options = Optionsexport default Chat