Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 6910 | Rev 6923 | Ir a la última revisión | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 6910 Rev 6911
Línea 1... Línea 1...
1
import React, { useEffect, useRef, useState } from 'react'
1
import React, { useEffect, useRef, useState } from 'react'
2
import { axios, scrollToBottom } from '../../../utils'
2
import { axios, scrollToBottom } from '../../utils'
3
import { addNotification } from '../../../redux/notification/notification.actions'
-
 
4
import { useDispatch } from 'react-redux'
3
import { useDispatch } from 'react-redux'
5
import SendIcon from '@mui/icons-material/Send'
-
 
6
import IconButton from '@mui/material/IconButton'
-
 
7
import MoreVertIcon from '@mui/icons-material/MoreVert'
-
 
8
import AttachFileIcon from '@mui/icons-material/AttachFile'
-
 
9
import InsertEmoticonIcon from '@mui/icons-material/InsertEmoticon'
4
import { addNotification } from '../../redux/notification/notification.actions'
10
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
5
import InboxIcon from '@mui/icons-material/Inbox'
11
 
6
 
12
// Components
-
 
13
import Message from '../../../components/chat/Message'
7
import Chat from './Chat'
14
import Emojione from '../emojione/Emojione'
8
import EmptySection from '../UI/EmptySection'
15
import { ConferenceModal } from '../../../chat/chat/personal-chat/PersonalChat'
-
 
16
import SendFileModal from '../../../chat/chat/personal-chat/send-file-modal/SendFileModal'
-
 
Línea 17... Línea 9...
17
 
9
 
18
const CHAT_TABS = {
10
const CHAT_TABS = {
19
  CHAT: 'CHAT',
11
  CHAT: 'CHAT',
20
  DEFAULT: 'DEFAULT',
12
  DEFAULT: 'DEFAULT',
21
  GROUP_MEMBERS: 'GROUP_MEMBERS',
13
  GROUP_MEMBERS: 'GROUP_MEMBERS',
22
  ADD_GROUP_MEMBER: 'ADD_GROUP_MEMBER',
14
  ADD_GROUP_MEMBER: 'ADD_GROUP_MEMBER',
Línea 23... Línea 15...
23
}
15
}
24
 
16
 
25
const ChatBox = ({ entity, timezones, changeTab }) => {
17
const ChatBox = ({ entity, changeTab }) => {
26
  const {
18
  const {
27
    url_get_all_messages,
19
    url_get_all_messages,
28
    url_mark_received,
20
    url_mark_received,
Línea 45... Línea 37...
45
  const [oldMessages, setOldMessages] = useState([])
37
  const [oldMessages, setOldMessages] = useState([])
46
  const [newMessages, setNewMessages] = useState([])
38
  const [newMessages, setNewMessages] = useState([])
47
  const [currentPage, setCurrentPage] = useState(1)
39
  const [currentPage, setCurrentPage] = useState(1)
48
  const [pages, setPages] = useState(1)
40
  const [pages, setPages] = useState(1)
Línea 49... Línea -...
49
 
-
 
50
  const [showEmojione, setShowEmojione] = useState(false)
-
 
51
  const [isShowFileModal, setIsShowFileModal] = useState(false)
41
 
52
  const [isShowConferenceModal, setisShowConferenceModal] = useState(false)
-
 
53
 
42
  const [isShowConferenceModal, setisShowConferenceModal] = useState(false)
54
  const [loading, setLoading] = useState(false)
-
 
55
  const [isSending, setIsSending] = useState(false)
-
 
Línea -... Línea 43...
-
 
43
  const [loading, setLoading] = useState(false)
56
  const [isGetting, setIsGetting] = useState(false)
44
 
57
 
-
 
58
  const dispatch = useDispatch()
45
  const [isGetting, setIsGetting] = useState(false)
59
 
-
 
Línea 60... Línea 46...
60
  const scrollRef = useRef(null)
46
  const dispatch = useDispatch()
61
  const inputTextEl = useRef(null)
47
  const scrollRef = useRef(null)
62
 
48
 
63
  // Messages getters
49
  // Messages getters
Línea 111... Línea 97...
111
        }
97
        }
112
      })
98
      })
113
      .finally(() => setIsGetting(false))
99
      .finally(() => setIsGetting(false))
114
  }
100
  }
Línea 115... Línea -...
115
 
-
 
116
  // Sender functions
-
 
117
  const onHandleSubmit = (e) => {
-
 
118
    e.preventDefault()
-
 
119
    const formData = new FormData()
-
 
120
    // eslint-disable-next-line no-undef
-
 
121
    formData.append('message', emojione.toShort(inputTextEl.current.value))
-
 
122
    inputTextEl.current.value = ''
-
 
123
 
-
 
124
    axios.post(url_send, formData).then(({ data }) => {
-
 
125
      if (!data.success) {
-
 
126
        setShowEmojione(false)
-
 
127
        dispatch(
-
 
128
          addNotification({
-
 
129
            style: 'danger',
-
 
130
            msg:
-
 
131
              typeof data.data === 'string'
-
 
132
                ? data.data
-
 
133
                : 'Ha ocurrido un error',
-
 
134
          })
-
 
135
        )
-
 
136
        return
-
 
137
      }
-
 
138
      setShowEmojione(false)
-
 
139
      scrollToBottom(scrollRef)
-
 
140
    })
-
 
141
  }
-
 
142
 
-
 
143
  const sendFile = (file) => {
-
 
144
    setIsSending(true)
-
 
145
    const formData = new FormData()
-
 
146
    formData.append('file', file)
-
 
147
 
-
 
148
    axios
-
 
149
      .post(url_upload, formData)
-
 
150
      .then(({ data: response }) => {
-
 
151
        const { success, data } = response
-
 
152
        if (!success) {
-
 
153
          const errorMessage =
-
 
154
            typeof data === 'string' ? data : 'Ha ocurrido un error'
-
 
155
          dispatch(addNotification({ style: 'success', msg: errorMessage }))
-
 
156
          return
-
 
157
        }
-
 
158
 
-
 
159
        toggleFileModal()
-
 
160
        scrollToBottom(scrollRef)
-
 
161
      })
-
 
162
      .finally(() => setIsSending(false))
-
 
163
  }
-
 
164
 
-
 
165
  const handleKeyDown = (e) => {
-
 
166
    if (e.key !== 'Enter') return false
-
 
167
  }
-
 
168
 
101
 
169
  // Modals handlers
-
 
170
  const toggleFileModal = () => {
-
 
171
    setIsShowFileModal(!isShowFileModal)
-
 
172
  }
-
 
173
 
-
 
174
  const toggleEmojione = () => {
-
 
175
    setShowEmojione(!showEmojione)
-
 
Línea 176... Línea 102...
176
  }
102
  // Modals handlers
177
 
103
 
178
  const toggleConferenceModal = () => {
104
  const toggleConferenceModal = () => {
Línea 179... Línea -...
179
    setisShowConferenceModal(!isShowConferenceModal)
-
 
180
  }
-
 
181
 
-
 
182
  // On select emoji
-
 
183
  const onClickEmoji = (event) => {
-
 
184
    const shortname = event.currentTarget.dataset.shortname
-
 
185
    const currentText = inputTextEl.current.value
-
 
186
    const cursorPosition = inputTextEl.current.selectionStart
-
 
187
    const textBehind = currentText.substring(0, cursorPosition)
-
 
188
    const textForward = currentText.substring(cursorPosition)
-
 
189
    // eslint-disable-next-line no-undef
-
 
190
    const unicode = emojione.shortnameToUnicode(shortname)
-
 
191
    inputTextEl.current.value = `${textBehind}${unicode}${textForward}`
-
 
192
    inputTextEl.current.focus()
-
 
193
    inputTextEl.current.setSelectionRange(
-
 
194
      cursorPosition + shortname.length,
-
 
195
      cursorPosition + shortname.length
-
 
196
    )
105
    setisShowConferenceModal(!isShowConferenceModal)
197
  }
106
  }
198
 
107
 
199
  // On interception handler
108
  // On interception handler
200
  const onIntersection = (entities) => {
109
  const onIntersection = (entities) => {
Línea 289... Línea 198...
289
    setCurrentPage(1)
198
    setCurrentPage(1)
290
  }, [entity])
199
  }, [entity])
Línea 291... Línea 200...
291
 
200
 
292
  return (
201
  return (
293
    <>
202
    <>
294
      <div className="chat">
203
      <Chat>
295
        <ChatBox.Header
-
 
296
          name={name}
204
        <Chat.Header
297
          profile={profile}
205
          onClose={() => changeTab(CHAT_TABS.DEFAULT)}
-
 
206
          options={type === 'group' ? groupOptions : options}
298
          options={type === 'group' ? groupOptions : options}
207
        >
299
          changeTab={() => changeTab(CHAT_TABS.DEFAULT)}
208
          <Chat.Title url={profile}>{name}</Chat.Title>
-
 
209
        </Chat.Header>
300
        />
210
 
301
        {![...newMessages, ...oldMessages].length ? (
-
 
302
          <div className="message-select-conversation">
211
        {![...newMessages, ...oldMessages].length ? (
303
            <div className="msgs-select-container">
212
          <EmptySection
304
              <i className="fas fa-inbox icon" />
213
            Icon={<InboxIcon />}
305
              <h3>No hay mensajes en esta conversación</h3>
-
 
306
            </div>
214
            message="No hay mensajes en esta conversación"
307
          </div>
215
          />
308
        ) : (
216
        ) : (
309
          <ChatBox.List
-
 
310
            isLastPage={currentPage >= pages}
217
          <Chat.List
311
            messages={[...oldMessages, ...newMessages]}
218
            messages={[...oldMessages, ...newMessages]}
-
 
219
            onPagination={onIntersection}
-
 
220
            currentPage={currentPage}
-
 
221
            loading={isGetting}
312
            onIntersection={onIntersection}
222
            pages={pages}
313
            scrollRef={scrollRef}
-
 
314
            isLoading={isGetting}
223
            scrollRef={scrollRef}
315
          />
224
          />
316
        )}
-
 
317
        <div className="chat__input-container">
-
 
318
          <form onSubmit={onHandleSubmit}>
-
 
319
            {showEmojione && <Emojione onClickEmoji={onClickEmoji} />}
-
 
320
            <button
-
 
321
              type="button"
-
 
322
              className="icon_btn"
-
 
323
              onClick={toggleFileModal}
-
 
324
            >
-
 
325
              <AttachFileIcon />
-
 
326
            </button>
-
 
327
            <button type="button" className="icon_btn" onClick={toggleEmojione}>
-
 
328
              <InsertEmoticonIcon />
-
 
329
            </button>
-
 
330
            <input
-
 
331
              type="text"
-
 
332
              className="chatInput"
-
 
333
              placeholder="Escribe un mensaje"
-
 
334
              onKeyDown={handleKeyDown}
-
 
335
              ref={inputTextEl}
-
 
336
            />
-
 
337
            <button type="submit" className="send_btn">
-
 
338
              <SendIcon />
-
 
339
            </button>
-
 
340
          </form>
-
 
341
        </div>
-
 
342
        <SendFileModal
-
 
343
          isShow={isShowFileModal}
-
 
344
          onHide={toggleFileModal}
-
 
345
          onComplete={sendFile}
-
 
346
          loading={isSending}
225
        )}
347
        />
226
 
348
        <ConferenceModal
-
 
349
          show={isShowConferenceModal}
227
        <Chat.SubmitForm
350
          zoomUrl={url_zoom}
228
          sendUrl={url_send}
351
          timezones={timezones}
229
          uploadUrl={url_upload}
352
          onCreate={toggleConferenceModal}
230
          onSubmit={() => scrollToBottom(scrollRef)}
353
        />
231
        />
354
      </div>
-
 
355
    </>
-
 
356
  )
-
 
357
}
-
 
358
const Header = ({ name, profile, options, changeTab }) => {
-
 
359
  return (
-
 
360
    <>
232
      </Chat>
361
      <div className="chat_header">
233
      {/* <ConferenceModal
362
        <IconButton onClick={changeTab}>
234
        show={isShowConferenceModal}
363
          <ArrowBackIcon />
235
        zoomUrl={url_zoom}
364
        </IconButton>
236
        timezones={timezones}
365
        <a href={profile}>
-
 
366
          <h2>{name}</h2>
237
        onCreate={toggleConferenceModal}
367
        </a>
-
 
368
        <Header.Options options={options} />
-
 
369
      </div>
238
      /> */}
370
    </>
239
    </>
371
  )
240
  )
Línea 372... Línea -...
372
}
-
 
373
 
-
 
374
const List = ({
-
 
375
  messages,
-
 
376
  onIntersection,
-
 
377
  isLastPage,
-
 
378
  scrollRef,
-
 
379
  isLoading,
-
 
380
}) => {
-
 
381
  const loadMoreEl = useRef()
-
 
382
 
-
 
383
  useEffect(() => {
-
 
384
    const observer = new IntersectionObserver(onIntersection)
-
 
385
 
-
 
386
    if (loadMoreEl.current) {
-
 
387
      observer.observe(loadMoreEl.current)
-
 
388
    }
-
 
389
 
-
 
390
    return () => {
-
 
391
      observer.disconnect()
-
 
392
    }
-
 
393
  }, [messages])
-
 
394
 
-
 
395
  return (
-
 
396
    <div className="messages_container" ref={scrollRef}>
-
 
397
      <div className="message_wrapper">
-
 
398
        {!isLastPage && !isLoading && <p ref={loadMoreEl}>Cargando...</p>}
-
 
399
        {messages.map((message) => (
-
 
400
          <Message message={message} key={message.id} />
-
 
401
        ))}
-
 
402
      </div>
-
 
403
    </div>
-
 
404
  )
-
 
405
}
-
 
406
 
-
 
407
const Options = ({ options }) => {
-
 
408
  const [isShowMenu, setIsShowMenu] = useState(false)
-
 
409
 
-
 
410
  const toggleOptions = () => {
-
 
411
    setIsShowMenu(!isShowMenu)
-
 
412
  }
-
 
413
 
-
 
414
  return (
-
 
415
    <div className="header-options">
-
 
416
      <IconButton onClick={toggleOptions}>
-
 
417
        <MoreVertIcon />
-
 
418
      </IconButton>
-
 
419
      <div className="position-relative">
-
 
420
        <div className={`feed-options ${isShowMenu ? 'active' : ''}`}>
-
 
421
          <ul>
-
 
422
            {options.map((option, index) => {
-
 
423
              if (!option.url) {
-
 
424
                return null
-
 
425
              }
-
 
426
 
-
 
427
              return (
-
 
428
                <li key={index}>
-
 
429
                  <button
-
 
430
                    className="btn option-btn"
-
 
431
                    onClick={() => {
-
 
432
                      option.action()
-
 
433
                      toggleOptions()
-
 
434
                    }}
-
 
435
                  >
-
 
436
                    {option.label}
-
 
437
                  </button>
-
 
438
                </li>
-
 
439
              )
-
 
440
            })}
-
 
441
          </ul>
-
 
442
        </div>
-
 
443
      </div>
-
 
444
    </div>
-
 
445
  )
-
 
446
}
-
 
447
 
-
 
448
ChatBox.Header = Header
-
 
449
ChatBox.List = List
-
 
450
Header.Options = Options
241
}