Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 5606 | 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'

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="d-flex align-items-center justify-content-center position-relative">
        <a href={selectedConversation.profile}>
          <h2 className="chat-header">{selectedConversation.name}</h2>
        </a>
        <div
          className="cursor-pointer d-flex align-items-center"
          style={{ position: 'absolute', right: '1rem' }}
        >
          <img
            src="/images/icons/options.png"
            className="cursor-pointer img-icon options"
            onClick={() => setDisplayOptions(!displayOptions)}
          />
          <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>
          <ConfirmModal
            show={isShowConfirm}
            onClose={toggleConfirmModal}
            onAccept={deleteConversation}
            acceptLabel="Aceptar"
          />
        </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>
  )
}

export default Chatmail