Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 5933 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
5242 stevensc 1
import React, { useEffect, useRef, useState } from 'react'
6753 stevensc 2
import { axios, scrollToBottom } from '../../utils'
5253 stevensc 3
import { useDispatch } from 'react-redux'
4
import { addNotification } from '../../redux/notification/notification.actions'
6753 stevensc 5
import IconButton from '@mui/material/IconButton'
6
import MoreVertIcon from '@mui/icons-material/MoreVert'
7
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
5253 stevensc 8
import QuestionAnswerRoundedIcon from '@mui/icons-material/QuestionAnswerRounded'
6753 stevensc 9
 
5185 stevensc 10
import MessageBox from './MessageBox'
11
import MessageTemplate from './MessageTemplate'
6753 stevensc 12
import EmptySection from '../../shared/empty-section/EmptySection'
5601 stevensc 13
import ConfirmModal from '../../shared/confirm-modal/ConfirmModal'
6753 stevensc 14
import LoaderContainer from '../../app/components/UI/LoaderContainer'
15
import Spinner from '../../shared/loading-spinner/Spinner'
16
import { getMessagesDifferences } from '../../services/chat'
1 www 17
 
5239 stevensc 18
const DEFAULT_PAGES = { current: 1, last: 1 }
19
 
3074 stevensc 20
const Chatmail = ({
6753 stevensc 21
  messagesUrl = '',
5185 stevensc 22
  selectedConversation = null,
5601 stevensc 23
  setConversation = () => null,
1741 stevensc 24
}) => {
5239 stevensc 25
  const [oldMessages, setOldMessages] = useState([])
26
  const [messages, setMessages] = useState([])
27
  const [pages, setPages] = useState(DEFAULT_PAGES)
28
  const [loading, setLoading] = useState(false)
6753 stevensc 29
  const [isGetting, setIsGetting] = useState(false)
5601 stevensc 30
  const [isShowConfirm, setIsShowConfirm] = useState(false)
5250 stevensc 31
  const messagesList = useRef(null)
5239 stevensc 32
  const dispatch = useDispatch()
835 stevensc 33
 
6753 stevensc 34
  const getMessages = () => {
5239 stevensc 35
    try {
6753 stevensc 36
      const controller = new AbortController()
37
      const query = (url = '', page = pages.current) =>
38
        axios
39
          .get(`${url}?page=${page}`, {
40
            signal: controller.signal,
41
          })
42
          .then((response) => response.data)
5239 stevensc 43
 
6753 stevensc 44
      return { query, controller }
5247 stevensc 45
    } catch (error) {
6753 stevensc 46
      dispatch(addNotification({ style: 'danger', message: 'Error: ' + error }))
47
      throw new Error(error)
5247 stevensc 48
    }
49
  }
50
 
6753 stevensc 51
  const getMoreMessages = () => {
52
    setLoading(true)
5247 stevensc 53
 
6753 stevensc 54
    const { query } = getMessages()
55
    query(messagesUrl, pages.current)
56
      .then(({ success, data, pagination }) => {
57
        if (!success) {
58
          const errorMessage = data ?? 'Ha ocurrido un error'
59
          dispatch(addNotification({ style: 'danger', msg: errorMessage }))
60
          return
61
        }
5247 stevensc 62
 
6753 stevensc 63
        if (pagination.current > 1) {
64
          setOldMessages((prevOldMessages) => [
65
            ...data.reverse(),
66
            ...prevOldMessages,
67
          ])
68
        }
5239 stevensc 69
 
6753 stevensc 70
        setPages((prevPages) => ({
71
          ...prevPages,
72
          last: pagination.last,
73
        }))
74
      })
75
      .catch((error) => {
76
        const errorMessage = 'Error: ' + error
77
        dispatch(addNotification({ style: 'danger', message: errorMessage }))
78
        throw new Error(error)
79
      })
80
      .finally(() => setLoading(false))
81
  }
5247 stevensc 82
 
6753 stevensc 83
  const hearbeat = () => {
84
    setIsGetting(true)
85
    const { query } = getMessages()
5239 stevensc 86
 
6753 stevensc 87
    query(messagesUrl, 1)
88
      .then(({ success, data, pagination }) => {
89
        if (!success) {
90
          const errorMessage = data ?? 'Ha ocurrido un error'
91
          dispatch(addNotification({ style: 'danger', msg: errorMessage }))
92
          return
93
        }
94
 
95
        const newMessages = getMessagesDifferences(messages, data)
96
 
97
        console.log(newMessages)
98
        if (newMessages.length) {
99
          setMessages((prevMessages) => [
100
            ...prevMessages,
101
            ...newMessages.reverse(),
102
          ])
103
        }
104
 
105
        setPages((prevPages) => ({
106
          ...prevPages,
107
          last: pagination.last,
108
        }))
109
      })
110
      .catch((err) => {
111
        const errorMessage = 'Error: ' + err
112
        dispatch(addNotification({ style: 'danger', message: errorMessage }))
113
        throw new Error(err)
114
      })
115
      .finally(() => setIsGetting(false))
5239 stevensc 116
  }
117
 
6753 stevensc 118
  const loadMore = () => {
119
    setLoading(true)
120
    setPages((prevPages) => ({ ...prevPages, current: prevPages.current + 1 }))
121
  }
122
 
123
  const toggleConfirmModal = () => {
124
    setIsShowConfirm(!isShowConfirm)
125
  }
126
 
127
  const sendMessage = async (sendUrl = '', message = {}) => {
5239 stevensc 128
    try {
129
      const formData = new FormData()
130
 
5601 stevensc 131
      Object.entries(message).forEach(([key, value]) =>
132
        formData.append(key, value)
133
      )
5239 stevensc 134
 
6753 stevensc 135
      await axios.post(sendUrl, formData)
136
 
137
      scrollToBottom(messagesList)
5239 stevensc 138
    } catch (error) {
139
      const errorMessage = new Error(error)
140
      dispatch(addNotification({ style: 'danger', msg: errorMessage.message }))
141
    }
142
  }
143
 
5603 stevensc 144
  const deleteConversation = () => {
5617 stevensc 145
    axios.post(selectedConversation.delete_link).then(({ data: response }) => {
146
      const { success, data } = response
5601 stevensc 147
 
5617 stevensc 148
      if (!success) {
149
        dispatch(addNotification({ style: 'danger', msg: data }))
150
        return
151
      }
5601 stevensc 152
 
5617 stevensc 153
      dispatch(addNotification({ style: 'success', msg: data }))
6753 stevensc 154
      toggleConfirmModal()
5617 stevensc 155
      setConversation(null)
156
    })
5601 stevensc 157
  }
158
 
5185 stevensc 159
  useEffect(() => {
6753 stevensc 160
    getMoreMessages()
161
  }, [pages.current])
5239 stevensc 162
 
5242 stevensc 163
  useEffect(() => {
6753 stevensc 164
    setMessages([])
165
    setOldMessages([])
5247 stevensc 166
    setPages(DEFAULT_PAGES)
167
  }, [selectedConversation])
168
 
169
  useEffect(() => {
6753 stevensc 170
    if (isGetting) return
5239 stevensc 171
 
6753 stevensc 172
    const messagesInterval = setTimeout(() => {
173
      hearbeat()
174
    }, 2000)
5197 stevensc 175
 
6753 stevensc 176
    return () => {
177
      clearTimeout(messagesInterval)
5253 stevensc 178
    }
6753 stevensc 179
  }, [isGetting])
917 stevensc 180
 
5185 stevensc 181
  return (
5933 stevensc 182
    <>
183
      <div className="chat">
6753 stevensc 184
        <Chatmail.Header
185
          name={selectedConversation.name}
186
          profile={selectedConversation.profile}
187
          options={[
188
            {
189
              url: selectedConversation.delete_link,
190
              label: 'Borrar convesación',
191
              action: toggleConfirmModal,
192
            },
193
          ]}
194
          changeTab={() => setConversation(null)}
195
        />
196
        {![...messages, ...oldMessages].length ? (
197
          <EmptySection
198
            message="No hay mensajes en esta conversación"
199
            Icon={<QuestionAnswerRoundedIcon />}
200
          />
201
        ) : (
202
          <Chatmail.List
203
            isLastPage={pages.current >= pages.last}
204
            messages={[...oldMessages, ...messages]}
205
            onIntersection={loadMore}
206
            scrollRef={messagesList}
207
            isLoading={loading}
208
          />
209
        )}
5933 stevensc 210
        <MessageBox
6753 stevensc 211
          onSend={sendMessage}
5933 stevensc 212
          sendUrl={selectedConversation.send_link}
213
        />
5185 stevensc 214
      </div>
5933 stevensc 215
      <ConfirmModal
216
        show={isShowConfirm}
217
        onClose={toggleConfirmModal}
218
        onAccept={deleteConversation}
219
        acceptLabel="Aceptar"
5601 stevensc 220
      />
5933 stevensc 221
    </>
5185 stevensc 222
  )
3074 stevensc 223
}
224
 
6753 stevensc 225
const Header = ({ name, profile, options, changeTab }) => {
226
  return (
227
    <>
228
      <div className="chat_header">
229
        <IconButton onClick={changeTab}>
230
          <ArrowBackIcon />
231
        </IconButton>
232
        <a href={profile}>
233
          <h2>{name}</h2>
234
        </a>
235
        <Header.Options options={options} />
236
      </div>
237
    </>
238
  )
239
}
240
 
241
const List = ({
242
  messages,
243
  onIntersection,
244
  isLastPage,
245
  scrollRef,
246
  isLoading,
247
}) => {
248
  const loadMoreEl = useRef(null)
249
 
250
  useEffect(() => {
251
    const observer = new IntersectionObserver((entries) => {
252
      if (entries[0].isIntersecting && !isLoading) {
253
        onIntersection()
254
      }
255
    })
256
 
257
    if (loadMoreEl.current === null) {
258
      return
259
    }
260
 
261
    observer.observe(loadMoreEl.current)
262
 
263
    return () => {
264
      observer.disconnect()
265
    }
266
  }, [isLoading, onIntersection])
267
 
268
  return (
269
    <div className="messages_container" ref={scrollRef}>
270
      <div className="message_wrapper">
271
        {!isLastPage && <p ref={loadMoreEl}>Cargando...</p>}
272
        {isLoading && (
273
          <LoaderContainer>
274
            <Spinner />
275
          </LoaderContainer>
276
        )}
277
        {messages.map((message, index) => (
278
          <MessageTemplate message={message} key={JSON.stringify(message)} />
279
        ))}
280
      </div>
281
    </div>
282
  )
283
}
284
 
285
const Options = ({ options }) => {
286
  const [isShowMenu, setIsShowMenu] = useState(false)
287
 
288
  const toggleOptions = () => {
289
    setIsShowMenu(!isShowMenu)
290
  }
291
 
292
  return (
293
    <div className="header-options">
294
      <IconButton onClick={toggleOptions}>
295
        <MoreVertIcon />
296
      </IconButton>
297
      <div className="position-relative">
298
        <div className={`feed-options ${isShowMenu ? 'active' : ''}`}>
299
          <ul>
300
            {options.map((option, index) => {
301
              if (!option.url) {
302
                return null
303
              }
304
 
305
              return (
306
                <li key={index}>
307
                  <button
308
                    className="btn option-btn"
309
                    onClick={() => {
310
                      option.action()
311
                      toggleOptions()
312
                    }}
313
                  >
314
                    {option.label}
315
                  </button>
316
                </li>
317
              )
318
            })}
319
          </ul>
320
        </div>
321
      </div>
322
    </div>
323
  )
324
}
325
 
326
Chatmail.Header = Header
327
Chatmail.List = List
328
Header.Options = Options
329
 
5185 stevensc 330
export default Chatmail