Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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