Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 5058 | Rev 5206 | Ir a la última revisión | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
5195 stevensc 1
/* eslint-disable camelcase */
3094 stevensc 2
/* eslint-disable react/prop-types */
5195 stevensc 3
import React, { useState, useRef, useEffect } from 'react'
4
import { axios } from '../../../utils'
5
import styled from 'styled-components'
6
import Emojione from './emojione/Emojione'
7
import SendFileModal from './send-file-modal/SendFileModal'
8
import ConfirmModal from '../../../shared/confirm-modal/ConfirmModal'
9
import MessageTemplate from './messageTemplate/MessageTemplate'
10
import { Modal } from 'react-bootstrap'
11
import { useForm } from 'react-hook-form'
12
import FormErrorFeedback from '../../../shared/form-error-feedback/FormErrorFeedback'
4119 stevensc 13
import 'react-datetime/css/react-datetime.css'
5195 stevensc 14
import Datetime from 'react-datetime'
15
import { addNotification } from '../../../redux/notification/notification.actions'
16
import Spinner from '../../../shared/loading-spinner/Spinner'
17
import { useDispatch } from 'react-redux'
4386 stevensc 18
import SearchIcon from '@mui/icons-material/Search'
1 www 19
 
20
const StyledChatHead = styled.div`
21
  .notify {
22
    animation: notify 2s infinite;
23
  }
24
 
25
  @keyframes notify {
26
    0% {
27
      background-color: unset;
28
    }
29
    50% {
30
      background-color: #00b0ff;
31
    }
32
    100% {
33
      background-color: unset;
34
    }
35
  }
5195 stevensc 36
`
1 www 37
 
38
const StyledShowOptions = styled.div`
39
  height: 342px;
40
  flex-direction: column;
5195 stevensc 41
  gap: 0.5rem;
1 www 42
  overflow-y: auto;
43
  position: relative;
44
  &.show {
45
    display: flex;
46
  }
47
  &.hide {
48
    display: none;
49
  }
50
  .optionBack {
51
    margin: 1rem 0 0.5rem 1rem;
52
    cursor: pointer;
53
  }
54
  .optionsTab {
55
    &__option {
56
      padding: 0.5rem;
57
      border-bottom: 1px solid #e2e2e2;
58
      cursor: pointer;
59
      &:hover {
60
        background-color: #e2e2e2;
61
      }
62
      &__icon {
63
        margin-right: 0.3rem;
64
      }
65
    }
66
  }
67
  .addPersonToGroupTab {
68
    display: flex;
69
    flex-direction: column;
70
    &__person {
71
      display: flex;
72
      justify-content: space-between;
73
      align-items: center;
74
      padding: 0.2rem 0.5rem;
75
      border-bottom: 1px solid #e2e2e2;
76
    }
77
  }
5195 stevensc 78
`
1 www 79
 
4119 stevensc 80
const PersonalChat = ({ entity, onClose, onMinimize, onRead, not_seen_messages, minimized, timezones }) => {
1 www 81
  const {
82
    id,
83
    image,
84
    name,
85
    online,
86
    type,
87
    url_get_all_messages,
88
    url_send,
89
    url_upload,
90
    profile,
91
    // group
92
    url_leave,
93
    url_delete,
94
    url_add_user_to_group,
95
    url_get_contact_group_list,
96
    url_get_contacts_availables_for_group,
4134 stevensc 97
    url_zoom
5195 stevensc 98
  } = entity
1 www 99
 
100
  // states
5195 stevensc 101
  const [messages, setMessages] = useState([])
102
  const [responseMessage, setResponseMessage] = useState(null)
103
  const [oldMessages, setOldMessages] = useState([])
104
  const [currentPage, setCurrentPage] = useState(1)
105
  const [pages, setPages] = useState(1)
106
  const [showOptions, setShowOptions] = useState(false)
107
  const [optionTab, setOptionTab] = useState('default')
108
  const [availableContactsToAdd, setAvailableContactsToAdd] = useState([])
109
  const [groupContactsList, setGroupContactsList] = useState([])
110
  const [confirmModalShow, setConfirmModalShow] = useState(false)
111
  const [showEmojiTab, setShowEmojiTab] = useState(false)
112
  const [shareFileModalShow, setShareFileModalShow] = useState(false)
113
  const [showConferenceModal, setShowConferenceModal] = useState(false)
114
  const [loading, setLoading] = useState(false)
115
  const [search, setSearch] = useState('')
1 www 116
 
4390 stevensc 117
  const filtredGroupList = groupContactsList.filter((conversation) => conversation.name.toLowerCase().includes(search.toLowerCase()))
4386 stevensc 118
 
1 www 119
  // refs
5195 stevensc 120
  const conversationListEl = useRef(null)
121
  const loader = useRef(null)
122
  const modalActionUrl = useRef('')
123
  const chatboxEl = useRef(null)
124
  const textAreaEl = useRef(null)
1 www 125
 
126
  // optionTabs
127
  const optionTabs = {
5195 stevensc 128
    add_person_to_group: 'add_person_to_group',
129
    group_contacts_list: 'group_contacts_list',
4116 stevensc 130
    meet: 'meet',
5195 stevensc 131
    default: 'default'
132
  }
1 www 133
 
134
  const handleActive = () => {
5195 stevensc 135
    onRead(entity)
136
    onMinimize(entity)
137
  }
1 www 138
 
139
  const handleGetMessages = async () => {
3122 stevensc 140
    setLoading(true)
5195 stevensc 141
    const response = await axios.get(url_get_all_messages)
142
    const resData = response.data
1 www 143
    if (!resData.success) {
5195 stevensc 144
      return ('ha ocurrido un error', resData)
1 www 145
    }
5195 stevensc 146
    const updatedMessages = [...resData.data.items].reverse()
1 www 147
    const newMessages = updatedMessages.reduce((acum, updatedMessage) => {
3089 stevensc 148
      if (messages.findIndex((message) => message.id === updatedMessage.id) === -1) {
5195 stevensc 149
        acum = [...acum, updatedMessage]
1 www 150
      }
5195 stevensc 151
      return acum
152
    }, [])
3089 stevensc 153
 
1 www 154
    if (newMessages.length > 0) {
5195 stevensc 155
      setMessages([...messages, ...newMessages])
3122 stevensc 156
      setLoading(false)
5195 stevensc 157
      setPages(resData.data.pages)
158
      scrollToBottom()
3090 stevensc 159
    } else {
5195 stevensc 160
      setMessages([...updatedMessages])
3122 stevensc 161
      setLoading(false)
1 www 162
    }
5195 stevensc 163
  }
1 www 164
 
165
  const handleLoadMore = async () => {
936 stevensc 166
    await axios.get(`${url_get_all_messages}?page=${currentPage}`)
1 www 167
      .then((response) => {
5195 stevensc 168
        const resData = response.data
1 www 169
        if (resData.success) {
170
          if (resData.data.page > 1) {
5195 stevensc 171
            const updatedOldMessages = [...resData.data.items].reverse()
172
            setOldMessages([...updatedOldMessages, ...oldMessages])
986 stevensc 173
            /* scrollDownBy(100); */
1 www 174
          }
175
        }
5195 stevensc 176
      })
177
  }
1 www 178
 
3122 stevensc 179
  const handleCloseChat = () => onClose(entity)
1 www 180
 
181
  const handleChatBoxKeyDown = async (e) => {
5195 stevensc 182
    if (e.key === 'Enter') {
183
      e.preventDefault()
184
      const message = e.target.value
185
      const formData = new FormData()
186
      formData.append('message', emojione.toShort(message))
2181 stevensc 187
      await axios.post(url_send, formData).then((response) => {
5195 stevensc 188
        const resData = response.data
2181 stevensc 189
        if (resData.success) {
2188 stevensc 190
          let newMessage = resData.data
2186 stevensc 191
 
192
          online
2188 stevensc 193
            ? newMessage = { ...newMessage, not_received: false }
194
            : newMessage = { ...newMessage, not_received: true }
2186 stevensc 195
 
2189 stevensc 196
          setMessages([...messages, newMessage])
2181 stevensc 197
        }
5195 stevensc 198
      })
199
      e.target.value = ''
2189 stevensc 200
      /* await handleGetMessages(); */
5195 stevensc 201
      setShowEmojiTab(false)
1778 stevensc 202
      setResponseMessage(null)
1 www 203
    }
5195 stevensc 204
  }
1 www 205
 
206
  const handleShowOptions = () => {
5195 stevensc 207
    onMinimize(entity, false)
208
    setShowOptions(!showOptions)
209
  }
1 www 210
 
211
  const handleChangeTab = (tab) => {
5195 stevensc 212
    setOptionTab(tab)
213
  }
1 www 214
 
215
  const handleAddPersonToGroup = async (id) => {
5195 stevensc 216
    const formData = new FormData()
217
    formData.append('uid', id)
1 www 218
    await axios.post(url_add_user_to_group, formData).then((response) => {
5195 stevensc 219
      const resData = response.data
1 www 220
      if (resData.success) {
5195 stevensc 221
        loadPersonsAvailable()
1 www 222
      }
5195 stevensc 223
    })
224
  }
1 www 225
 
226
  const handleConfirmModalAction = async () => {
3122 stevensc 227
    try {
3788 stevensc 228
      const { data } = await axios.post(modalActionUrl.current)
3122 stevensc 229
      if (!data.success) console.log('Error in confirm modal action')
3788 stevensc 230
      handleConfirmModalShow()
5195 stevensc 231
      onClose(entity)
3788 stevensc 232
      return
3122 stevensc 233
    } catch (error) {
234
      console.log(error)
235
    }
5195 stevensc 236
  }
1 www 237
 
238
  const handleObserver = (entities) => {
5195 stevensc 239
    const target = entities[0]
1 www 240
    if (target.isIntersecting) {
5195 stevensc 241
      setCurrentPage((prevState) => prevState + 1)
1 www 242
    }
5195 stevensc 243
  }
1 www 244
 
245
  const scrollToBottom = () => {
3056 stevensc 246
    if (conversationListEl.current) {
1 www 247
      conversationListEl.current.scrollTop =
5195 stevensc 248
        conversationListEl.current.scrollHeight * 9
1 www 249
    }
5195 stevensc 250
  }
1 www 251
 
252
  const handleShowEmojiTab = () => {
5195 stevensc 253
    setShowEmojiTab(!showEmojiTab)
1 www 254
    // smiley_tpl(`${id}`);
5195 stevensc 255
  }
1 www 256
 
257
  const handleClickEmoji = (e) => {
5195 stevensc 258
    const shortname = e.currentTarget.dataset.shortname
259
    const currentText = textAreaEl.current.value
260
    const cursorPosition = textAreaEl.current.selectionStart
261
    const textBehind = currentText.substring(0, cursorPosition)
262
    const textForward = currentText.substring(cursorPosition)
263
    const unicode = emojione.shortnameToUnicode(shortname)
264
    textAreaEl.current.value = `${textBehind}${unicode}${textForward}`
265
    textAreaEl.current.focus()
1 www 266
    textAreaEl.current.setSelectionRange(
267
      cursorPosition + unicode.length,
268
      cursorPosition + unicode.length
5195 stevensc 269
    )
270
  }
1 www 271
 
272
  // useEffect(() => {
273
  //   setMessages([...oldMessages, ...newMessages]);
274
  // }, [newMessages, oldMessages]);
275
 
276
  // getMessageOnMaximize and subscribe to infinite Loader
277
  useEffect(async () => {
5195 stevensc 278
    const options = {
3090 stevensc 279
      root: null,
5195 stevensc 280
      rootMargin: '20px',
281
      treshold: 1.0
282
    }
283
    const observer = new IntersectionObserver(handleObserver, options)
1 www 284
    if (!minimized) {
5195 stevensc 285
      await handleGetMessages()
1 www 286
      // loader observer
287
      if (loader.current) {
5195 stevensc 288
        observer.observe(loader.current)
1 www 289
      }
290
    }
291
    return () => {
292
      if (loader.current) {
5195 stevensc 293
        observer.unobserve(loader.current)
1 www 294
      }
5195 stevensc 295
    }
296
  }, [minimized])
1 www 297
 
298
  // LoadMore on change page
299
  useEffect(() => {
5195 stevensc 300
    let loadMore = () => handleLoadMore()
928 stevensc 301
    loadMore()
1 www 302
    return () => {
5195 stevensc 303
      loadMore = null
304
    }
305
  }, [currentPage])
1 www 306
 
307
  // getMessagesInterval
308
  useEffect(() => {
932 stevensc 309
    if (window.location.pathname === '/group/my-groups') {
38 steven 310
      const items = document.getElementsByClassName('sc-jSgupP')
5195 stevensc 311
      if (items && items.length > 0) { items[0].style.display = 'none' }
38 steven 312
    }
5195 stevensc 313
  }, [minimized])
3122 stevensc 314
 
315
  useEffect(() => {
5195 stevensc 316
    let timer
3119 stevensc 317
    if (!minimized && !loading) {
5195 stevensc 318
      timer = setTimeout(() => handleGetMessages(), 1000)
1 www 319
    }
3120 stevensc 320
    return () => {
5195 stevensc 321
      clearTimeout(timer)
322
    }
323
  }, [minimized, loading])
3122 stevensc 324
 
3788 stevensc 325
  const handleConfirmModalShow = () => setConfirmModalShow(!confirmModalShow)
1 www 326
 
3788 stevensc 327
  const handleConfirmModalAccept = () => handleConfirmModalAction()
1 www 328
 
329
  const handleShareFileModalShow = () => {
5195 stevensc 330
    setShareFileModalShow(!shareFileModalShow)
331
  }
1 www 332
 
1300 stevensc 333
  const handleResponseMessage = (element) => {
3059 stevensc 334
    element.mtype === 'text'
335
      ? setResponseMessage(element)
336
      : setResponseMessage({ ...element, m: 'Archivo adjunto' })
337
 
2765 stevensc 338
    textAreaEl.current && textAreaEl.current.focus()
5195 stevensc 339
  }
1300 stevensc 340
 
4116 stevensc 341
  const displayConferenceModal = () => setShowConferenceModal(!showConferenceModal)
4115 stevensc 342
 
1 www 343
  const messagesRender = () => {
344
    return (
345
      <React.Fragment>
5195 stevensc 346
        {currentPage < pages ? <li ref={loader}>Cargando...</li> : ''}
1 www 347
        {oldMessages.map((oldMessage) => (
3088 stevensc 348
          <MessageTemplate time={oldMessage.time} key={oldMessage.id} message={oldMessage} />
1 www 349
        ))}
1215 stevensc 350
        {messages.map((message, i) => {
5195 stevensc 351
          const currentTime = message.time
352
          const prevMessage = messages[i - 1]
2187 stevensc 353
 
5195 stevensc 354
          const dailys = ['mes', 'meses', 'semana', 'semanas', 'dia', 'dias', 'año', 'años']
355
          // const date = new Date(Date.now()).toLocaleDateString()
1215 stevensc 356
 
1216 stevensc 357
          if (prevMessage !== undefined) {
5195 stevensc 358
            const prevTime = messages[i - 1].time
2181 stevensc 359
 
1216 stevensc 360
            if (prevTime !== currentTime && dailys.includes(prevTime.split(' ')[1])) {
361
              return <>
2538 stevensc 362
                {/* <h2 className="text-center date-chat">{date}</h2> */}
1298 stevensc 363
                <MessageTemplate
3088 stevensc 364
                  key={message.id}
1298 stevensc 365
                  message={message}
3088 stevensc 366
                  time={message.time}
1300 stevensc 367
                  setResponseMessage={handleResponseMessage}
1298 stevensc 368
                  responseMessage={responseMessage}
369
                />
1216 stevensc 370
              </>
371
            }
1215 stevensc 372
          }
373
 
1300 stevensc 374
          return <MessageTemplate
3088 stevensc 375
            key={message.id}
1300 stevensc 376
            message={message}
3088 stevensc 377
            time={message.time}
1300 stevensc 378
            setResponseMessage={handleResponseMessage}
379
            responseMessage={responseMessage}
380
          />
1215 stevensc 381
        })}
1 www 382
      </React.Fragment>
5195 stevensc 383
    )
384
  }
1 www 385
 
386
  const optionRender = () => {
387
    switch (optionTab) {
388
      case optionTabs.add_person_to_group:
5195 stevensc 389
        return addPersonToGroupTab
1 www 390
      case optionTabs.group_contacts_list:
5195 stevensc 391
        return groupContactsListTab
4116 stevensc 392
      case optionTabs.meet:
5195 stevensc 393
        return meetingOptionsTab
1 www 394
      default:
5195 stevensc 395
        return optionsDefaultTab
1 www 396
    }
5195 stevensc 397
  }
1 www 398
 
399
  // useEffect for tabs changing
400
  useEffect(() => {
401
    switch (optionTab) {
402
      case optionTabs.add_person_to_group:
5195 stevensc 403
        loadPersonsAvailable()
404
        break
1 www 405
      case optionTabs.group_contacts_list:
5195 stevensc 406
        loadGroupContacts()
407
        break
1 www 408
    }
5195 stevensc 409
  }, [optionTab])
1 www 410
 
411
  const loadPersonsAvailable = async () => {
412
    await axios.get(url_get_contacts_availables_for_group).then((response) => {
5195 stevensc 413
      const resData = response.data
1 www 414
      if (resData.success) {
5195 stevensc 415
        setAvailableContactsToAdd(resData.data)
1 www 416
      }
5195 stevensc 417
    })
418
  }
1 www 419
 
420
  const loadGroupContacts = async () => {
421
    await axios.get(url_get_contact_group_list).then((response) => {
5195 stevensc 422
      const resData = response.data
1 www 423
      if (resData.success) {
5195 stevensc 424
        setGroupContactsList(resData.data)
1 www 425
      }
5195 stevensc 426
    })
427
  }
1 www 428
 
429
  const handleDeletePersonFromGroup = async (urlDeletePersonFromGroup) => {
430
    await axios.post(urlDeletePersonFromGroup).then((response) => {
5195 stevensc 431
      const resData = response.data
1 www 432
      if (resData.success) {
5195 stevensc 433
        loadGroupContacts()
1 www 434
      }
5195 stevensc 435
    })
436
  }
1 www 437
 
438
  const optionsDefaultTab = (
439
    <React.Fragment>
440
      <span className="optionBack" onClick={() => handleShowOptions()}>
441
        <i className="fa icon-arrow-left"></i>
442
      </span>
443
      <div className="optionsTab">
444
        <ul>
445
          {!!url_get_contact_group_list && (
446
            <li
447
              className="optionsTab__option"
448
              onClick={() => handleChangeTab(optionTabs.group_contacts_list)}
449
            >
450
              <span className="optionsTab__option__icon">
451
                <i className="fa fa-group"></i>
452
              </span>
453
              Integrantes
454
            </li>
455
          )}
456
          {!!url_add_user_to_group && (
457
            <li
458
              className="optionsTab__option"
459
              onClick={() => handleChangeTab(optionTabs.add_person_to_group)}
460
            >
461
              <span className="optionsTab__option__icon">
462
                <i className="fa fa-user-plus"></i>
463
              </span>
464
              Agregar contactos
465
            </li>
466
          )}
4153 stevensc 467
          {
468
            url_zoom &&
469
            <li
470
              className="optionsTab__option"
471
              onClick={displayConferenceModal}
472
            >
473
              <span className="optionsTab__option__icon">
474
                <i className="fa fa-user-plus" />
475
              </span>
476
              Crear conferencia
477
            </li>
478
          }
1 www 479
          {!!url_delete && (
480
            <li
481
              className="optionsTab__option"
5195 stevensc 482
              style={{ color: 'red' }}
1 www 483
              onClick={() => {
5195 stevensc 484
                handleConfirmModalShow()
485
                modalActionUrl.current = url_delete
1 www 486
              }}
487
            >
488
              <span className="optionsTab__option__icon">
489
                <i className="fa fa-trash"></i>
490
              </span>
491
              Eliminar grupo
492
            </li>
493
          )}
494
          {!!url_leave && (
495
            <li
496
              className="optionsTab__option"
5195 stevensc 497
              style={{ color: 'red' }}
1 www 498
              onClick={() => {
5195 stevensc 499
                handleConfirmModalShow()
500
                modalActionUrl.current = url_leave
1 www 501
              }}
502
            >
503
              <span className="optionsTab__option__icon">
504
                <i className="fa fa-user-times"></i>
505
              </span>
506
              Dejar grupo
507
            </li>
508
          )}
509
        </ul>
510
      </div>
511
    </React.Fragment>
5195 stevensc 512
  )
1 www 513
 
4115 stevensc 514
  const meetingOptionsTab = (
515
    <>
516
      <span className="optionBack" onClick={() => handleShowOptions()}>
517
        <i className="fa icon-arrow-left" />
518
      </span>
519
      <div className="optionsTab">
520
        <ul>
521
          <li
522
            className="optionsTab__option"
523
            onClick={displayConferenceModal}
524
          >
525
            <span className="optionsTab__option__icon">
526
              <i className="fa fa-user-plus" />
527
            </span>
528
            Crear conferencia
529
          </li>
530
        </ul>
531
      </div>
532
    </>
5195 stevensc 533
  )
4115 stevensc 534
 
1 www 535
  const addPersonToGroupTab = (
536
    <React.Fragment>
537
      <span
538
        className="optionBack"
539
        onClick={() => handleChangeTab(optionTabs.default)}
540
      >
541
        <i className="fa icon-arrow-left"></i>
542
      </span>
543
      <div className="addPersonToGroupTab">
5195 stevensc 544
        {availableContactsToAdd.length
545
          ? (
546
              availableContactsToAdd.map(({ image, name, id }) => (
1 www 547
            <div className="addPersonToGroupTab__person" key={id}>
2664 stevensc 548
              <div className="d-inline-flex" style={{ gap: '5px' }}>
2663 stevensc 549
                <img
550
                  className="chat-image img-circle pull-left"
551
                  height="36"
552
                  width="36"
553
                  src={image}
554
                  alt="image-image"
555
                />
556
                <div className="name">{name}</div>
557
              </div>
1 www 558
              <span
559
                style={{
5195 stevensc 560
                  cursor: 'pointer'
1 www 561
                }}
562
                onClick={() => {
5195 stevensc 563
                  handleAddPersonToGroup(id)
1 www 564
                }}
565
              >
566
                <i className="fa fa-plus-circle"></i>
567
              </span>
568
            </div>
5195 stevensc 569
              ))
570
            )
571
          : (
1 www 572
          <div className="addPersonToGroupTab__person">No hay Contactos</div>
5195 stevensc 573
            )}
1 www 574
      </div>
575
    </React.Fragment>
5195 stevensc 576
  )
1 www 577
 
578
  const groupContactsListTab = (
4389 stevensc 579
    <>
4386 stevensc 580
      <span className="optionBack" onClick={() => handleChangeTab(optionTabs.default)}>
581
        <i className="fa icon-arrow-left" />
1 www 582
      </span>
4390 stevensc 583
      <div className='group__search'>
4386 stevensc 584
        <SearchIcon />
585
        <input
586
          type='text'
587
          placeholder='Buscar'
588
          onChange={(e) => setSearch(e.target.value)}
589
        />
590
      </div>
1 www 591
      <div className="addPersonToGroupTab">
4389 stevensc 592
        {filtredGroupList.length
593
          ? filtredGroupList.map(({ image, name, url_remove_from_group, id }) => {
594
            return (
1 www 595
              <div className="addPersonToGroupTab__person" key={id}>
5195 stevensc 596
                <div style={{ display: 'flex', alignItems: 'center' }}>
1 www 597
                  <img
598
                    className="chat-image img-circle pull-left"
599
                    height="36"
600
                    width="36"
601
                    src={image}
602
                    alt="image-image"
603
                  />
604
                  <div className="name">{name}</div>
605
                </div>
4389 stevensc 606
                {url_remove_from_group &&
607
                  <span className="cursor-pointer" onClick={() => handleDeletePersonFromGroup(url_remove_from_group)}>
608
                    <i className="fa fa-user-times" />
1 www 609
                  </span>
4389 stevensc 610
                }
1 www 611
              </div>
612
            )
4389 stevensc 613
          })
614
          : <div className="addPersonToGroupTab__person">No hay Contactos</div>
615
        }
1 www 616
      </div>
4389 stevensc 617
    </>
5195 stevensc 618
  )
1 www 619
 
620
  const userChat = (
4116 stevensc 621
    <>
3752 stevensc 622
      <div className="chatbox active-chat" style={{ display: 'block' }}>
1 www 623
        <div className="chatbox-icon">
624
          <div className="contact-floating red">
625
            <img className="chat-image img-circle pull-left" src={image} />
626
            <small className="unread-msg">2</small>
627
          </div>
628
        </div>
629
        <div className="panel personal-chat">
630
          <StyledChatHead>
5195 stevensc 631
            <div className={`panel-heading chatboxhead ${not_seen_messages ? 'notify' : ''}`}>
1 www 632
              <div className="panel-title">
633
                <img
634
                  className="chat-image img-circle pull-left"
635
                  height="36"
636
                  width="36"
637
                  src={image}
638
                  alt="avatar-image"
639
                />
640
                <div className="header-elements">
3056 stevensc 641
                  <a href={profile} target="_blank" rel="noreferrer">
1 www 642
                    {name}
643
                  </a>
644
                  <br />
5195 stevensc 645
                  <small className={`status ${online ? 'Online' : 'Offline'}`}>
646
                    <b>{online ? 'En línea' : 'Desconectado'}</b>
1 www 647
                  </small>
648
                  <div className="pull-right options">
4115 stevensc 649
                    <div className="btn-group uploadFile">
1 www 650
                      {/* <span>
651
                      <i className="fa fa-trash"></i>
652
                    </span> */}
653
                    </div>
4115 stevensc 654
                    <div className="btn-group">
1 www 655
                      {/* <span>
656
                      <i className="fa fa-trash"></i>
657
                    </span> */}
658
                    </div>
4117 stevensc 659
                    <div className="btn-group">
1 www 660
                      <span>
4154 stevensc 661
                        <i className="fa fa-gear" onClick={() => {
4116 stevensc 662
                          handleChangeTab(optionTabs.meet)
663
                          handleShowOptions()
4117 stevensc 664
                        }}
665
                        />
1 www 666
                      </span>
667
                    </div>
4115 stevensc 668
                    <div className="btn-group">
1 www 669
                      <span>
5195 stevensc 670
                        <i className={'fa fa-minus-circle'} onClick={handleActive} />
1 www 671
                      </span>
672
                    </div>
4115 stevensc 673
                    <div className="btn-group">
674
                      <span>
675
                        <i className="fa fa-times-circle" onClick={handleCloseChat} />
676
                      </span>
677
                    </div>
1 www 678
                  </div>
679
                </div>
680
              </div>
681
            </div>
682
          </StyledChatHead>
683
          <div
684
            className="panel-body"
5195 stevensc 685
            style={{ display: !minimized ? 'block' : 'none' }}
1 www 686
          >
5195 stevensc 687
            <StyledShowOptions className={` ${showOptions ? 'show' : 'hide'}`}>
4116 stevensc 688
              {optionRender()}
689
            </StyledShowOptions>
1 www 690
            <div
691
              id="uploader_'+chatboxtitle+'"
5195 stevensc 692
              style={{ display: 'none', height: '342px' }}
1 www 693
            >
694
              <p>
695
                Your browser does not have Flash, Silverlight or HTML5 support.
696
              </p>
697
            </div>
4116 stevensc 698
            <div
699
              className="chat-conversation"
5195 stevensc 700
              style={{ position: 'relative', display: showOptions ? 'none' : 'block' }}
4116 stevensc 701
            >
1 www 702
              <div className="reverseChatBox" ref={conversationListEl}>
703
                <ul
704
                  className="conversation-list chatboxcontent"
705
                  id="resultchat_'+chatboxtitle+'"
706
                >
707
                  {messagesRender()}
708
                </ul>
709
              </div>
3604 stevensc 710
              <div className="wchat-footer wchat-chat-footer">
1301 stevensc 711
                <div id="chatFrom" className="chatFrom">
2577 stevensc 712
                  {
5195 stevensc 713
                    responseMessage &&
714
                    <div className={responseMessage ? 'resp_messages-container active' : 'resp_messages-container'}>
2577 stevensc 715
                      <span>{`Respondiendo a ${responseMessage.user_name}`}</span>
716
                      <p>{responseMessage.m}</p>
717
                    </div>
718
                  }
1 www 719
                  <div className="block-wchat">
720
                    <button
721
                      className="icon ti-clip attachment font-24 btn-attach btn-attach uploadFile"
722
                      id="uploadFile"
723
                      onClick={handleShareFileModalShow}
724
                    ></button>
725
                    <button
726
                      className="icon ti-face-smile font-24 btn-emoji"
727
                      id="toggle-emoji"
728
                      onClick={handleShowEmojiTab}
729
                    ></button>
730
                    <div className="input-container">
731
                      <div className="input-emoji">
732
                        <div
733
                          className="input-placeholder"
5195 stevensc 734
                          style={{ visibility: 'hidden', display: 'none' }}
1 www 735
                        >
736
                          Escribe un mensaje
737
                        </div>
738
                        <textarea
739
                          className="input chatboxtextarea"
740
                          id="chatboxtextarea"
741
                          name="chattxt"
5195 stevensc 742
                          style={{ resize: 'none', height: '20px' }}
1 www 743
                          placeholder="Escribe un mensaje"
744
                          onKeyDown={handleChatBoxKeyDown}
745
                          ref={textAreaEl}
3045 stevensc 746
                          onBlur={() => responseMessage && setResponseMessage(null)}
3122 stevensc 747
                          onFocus={() => not_seen_messages && onRead(entity)}
748
                        />
1 www 749
                        <input
750
                          id="to_uname"
751
                          name="to_uname"
752
                          value="'+chatboxtitle+'"
753
                          type="hidden"
754
                        />
755
                        <input
756
                          id="from_uname"
757
                          name="from_uname"
758
                          value="Beenny"
759
                          type="hidden"
760
                        />
761
                      </div>
762
                    </div>
763
                  </div>
764
                </div>
5058 stevensc 765
 
766
                <div className="wchat-box-items-overlay-container">
5195 stevensc 767
                  <div className="target-emoji" style={{ display: showEmojiTab ? 'block' : 'none' }} id={`smileyPanel_${id}`}>
5058 stevensc 768
                    <Emojione onClickEmoji={handleClickEmoji} />
1 www 769
                  </div>
770
                </div>
5058 stevensc 771
 
1 www 772
              </div>
773
            </div>
774
          </div>
775
        </div>
776
      </div>
5052 stevensc 777
      <SendFileModal
778
        show={shareFileModalShow}
779
        onHide={() => setShareFileModalShow(false)}
780
        urlUpload={url_upload}
781
      />
4147 stevensc 782
      <ConferenceModal
783
        show={showConferenceModal}
784
        timezones={timezones}
785
        zoomUrl={url_zoom}
4149 stevensc 786
        onCreate={() => {
787
          handleShowOptions()
788
          displayConferenceModal()
789
        }}
4147 stevensc 790
      />
4116 stevensc 791
    </>
5195 stevensc 792
  )
1 www 793
 
794
  const groupChat = (
795
    <React.Fragment>
796
      <div
3752 stevensc 797
        className="chatbox active-chat "
1 www 798
        ref={chatboxEl}
799
      >
800
        <div className="chatbox-icon">
801
          <div className="contact-floating red">
802
            <img className="chat-image img-circle pull-left" src={image} />
803
            <small className="unread-msg">2</small>
804
          </div>
805
        </div>
806
        <div className="panel personal-chat">
807
          <StyledChatHead>
5195 stevensc 808
            <div className={`panel-heading chatboxhead ${not_seen_messages ? 'notify' : ''}`}>
1 www 809
              <div className="panel-title-group">
810
                <img
811
                  className="chat-image img-circle pull-left"
812
                  height="36"
813
                  width="36"
814
                  src="/images/users-group.png"
815
                  alt="avatar-image"
816
                />
817
                <div className="header-elements">
818
                  <p>{name}</p>
819
                  <br />
820
                  <div className="pull-right options">
821
                    <div
822
                      className="btn-group uploadFile"
823
                      id="uploadFile"
824
                      data-client="'+chatboxtitle+'"
825
                    >
826
                    </div>
3752 stevensc 827
                    <div className="btn-group">
1 www 828
                    </div>
829
                    <div
830
                      className="btn-group addUser"
831
                      data-client="8cb2a840-56c2-4f93-9cf1-27ad598acd8f"
832
                      data-name="Grupo de jesus"
833
                    >
834
                      <span>
835
                        <i
836
                          className="fa fa-gear"
837
                          onClick={handleShowOptions}
838
                        ></i>
839
                      </span>
840
                    </div>
3752 stevensc 841
                    <div className="btn-group">
1 www 842
                      <span>
843
                        <i
5195 stevensc 844
                          className={'fa fa-minus-circle'}
1 www 845
                          onClick={handleActive}
846
                        ></i>
847
                      </span>
848
                    </div>
3752 stevensc 849
                    <div className="btn-group">
1 www 850
                      <span>
851
                        <i
852
                          className="fa fa-times-circle"
853
                          onClick={handleCloseChat}
854
                        ></i>
855
                      </span>
856
                    </div>
857
                  </div>
858
                </div>
859
              </div>
860
            </div>
861
          </StyledChatHead>
862
          <div
863
            className="panel-body"
5195 stevensc 864
            style={{ display: !minimized ? 'block' : 'none' }}
1 www 865
          >
5195 stevensc 866
            <StyledShowOptions className={` ${showOptions ? 'show' : 'hide'}`}>
1 www 867
              {optionRender()}
868
            </StyledShowOptions>
869
 
870
            <div
871
              className="chat-conversation"
872
              style={{
5195 stevensc 873
                display: showOptions ? 'none' : 'block',
874
                position: 'relative'
1 www 875
              }}
876
            >
877
              <div className="reverseChatBox" ref={conversationListEl}>
878
                <ul
879
                  className="conversation-list chatboxcontent"
880
                  id="resultchat_'+chatboxtitle+'"
881
                >
882
                  {messagesRender()}
883
                </ul>
884
              </div>
3604 stevensc 885
              <div className="wchat-footer wchat-chat-footer">
1 www 886
                <div id="chatFrom">
887
                  <div className="block-wchat">
888
                    <button
889
                      className="icon ti-clip attachment font-24 btn-attach btn-attach uploadFile"
890
                      id="uploadFile"
891
                      onClick={handleShareFileModalShow}
892
                    ></button>
893
                    <button
894
                      className="icon ti-face-smile font-24 btn-emoji"
895
                      id="toggle-emoji"
896
                      onClick={handleShowEmojiTab}
897
                    ></button>
898
                    <div className="input-container">
899
                      <div className="input-emoji">
900
                        <div
901
                          className="input-placeholder"
5195 stevensc 902
                          style={{ visibility: 'hidden', display: 'none' }}
1 www 903
                        >
904
                          Escribe un mensaje
905
                        </div>
906
                        <textarea
907
                          className="input chatboxtextarea"
908
                          id="chatboxtextarea"
909
                          name="chattxt"
5195 stevensc 910
                          style={{ resize: 'none', height: '20px' }}
1 www 911
                          placeholder="Escribe un mensaje"
912
                          onKeyDown={handleChatBoxKeyDown}
913
                          ref={textAreaEl}
3122 stevensc 914
                          onFocus={() => not_seen_messages && onRead(entity)}
3045 stevensc 915
                          onBlur={() => responseMessage && setResponseMessage(null)}
1 www 916
                        ></textarea>
917
                        <input
918
                          id="to_uname"
919
                          name="to_uname"
920
                          value="'+chatboxtitle+'"
921
                          type="hidden"
922
                        />
923
                        <input
924
                          id="from_uname"
925
                          name="from_uname"
926
                          value="Beenny"
927
                          type="hidden"
928
                        />
929
                      </div>
930
                    </div>
931
                  </div>
932
                </div>
933
                <div className="wchat-box-items-positioning-container">
934
                  <div className="wchat-box-items-overlay-container">
935
                    <div
936
                      className="target-emoji"
5195 stevensc 937
                      style={{ display: showEmojiTab ? 'block' : 'none' }}
1 www 938
                    >
939
                      <div id={`smileyPanel_${id}`}>
940
                        <div>
941
                          <Emojione onClickEmoji={handleClickEmoji} />
942
                        </div>
943
                      </div>
944
                    </div>
945
                  </div>
946
                </div>
947
              </div>
948
            </div>
949
          </div>
950
        </div>
951
      </div>
952
      <ConfirmModal
953
        show={confirmModalShow}
954
        onClose={handleConfirmModalShow}
955
        onAccept={handleConfirmModalAccept}
956
      />
4152 stevensc 957
      <ConferenceModal
958
        show={showConferenceModal}
959
        timezones={timezones}
960
        zoomUrl={url_zoom}
961
        onCreate={() => {
962
          handleShowOptions()
963
          displayConferenceModal()
964
        }}
965
      />
5052 stevensc 966
      <SendFileModal
967
        show={shareFileModalShow}
968
        onHide={() => setShareFileModalShow(false)}
969
        urlUpload={url_upload}
970
      />
1 www 971
    </React.Fragment>
5195 stevensc 972
  )
1 www 973
 
974
  switch (type) {
5195 stevensc 975
    case 'user':
976
      return userChat
977
    case 'group':
978
      return groupChat
1 www 979
    default:
5195 stevensc 980
      break
1 www 981
  }
5195 stevensc 982
}
1 www 983
 
4115 stevensc 984
const StyleModal = ({
985
  title = 'Crea una conferencia',
986
  size = 'md',
987
  show = false,
988
  children
989
}) => {
990
  const [isShow, setIsShow] = useState(show)
991
 
4118 stevensc 992
  useEffect(() => {
993
    setIsShow(show)
994
  }, [show])
995
 
4115 stevensc 996
  const closeModal = () => setIsShow(false)
997
 
998
  return (
999
    <Modal
1000
      show={isShow}
1001
      onHide={closeModal}
5195 stevensc 1002
      style={{ overflowY: 'scroll' }}
4115 stevensc 1003
    >
1004
      <Modal.Header closeButton>
1005
        <Modal.Title>{title}</Modal.Title>
1006
      </Modal.Header>
1007
      <Modal.Body>
1008
        {children}
1009
      </Modal.Body>
1010
    </Modal>
1011
  )
1012
}
1013
 
5021 stevensc 1014
export const ConferenceModal = ({
4128 stevensc 1015
  show = false,
4134 stevensc 1016
  timezones = {},
4147 stevensc 1017
  zoomUrl = '',
1018
  onCreate = () => null
4115 stevensc 1019
}) => {
4130 stevensc 1020
  const dt = new Date()
4136 stevensc 1021
  const { handleSubmit, register, errors, reset } = useForm({ mode: 'all' })
4128 stevensc 1022
  const [date, setDate] = useState({
5195 stevensc 1023
    year: dt.toLocaleString('default', { year: 'numeric' }),
1024
    month: dt.toLocaleString('default', { month: '2-digit' }),
1025
    day: dt.toLocaleString('default', { day: '2-digit' })
4128 stevensc 1026
  })
5195 stevensc 1027
  const [time, setTime] = useState(dt.toLocaleString('es', { hour: 'numeric', minute: '2-digit', second: '2-digit' }))
4120 stevensc 1028
  const [coferenceType, setConferenceType] = useState(1)
4140 stevensc 1029
  const dispatch = useDispatch()
4115 stevensc 1030
 
4120 stevensc 1031
  const handleChange = (value) => setConferenceType(value)
1032
 
4128 stevensc 1033
  const handleDateTime = (value) => {
1034
    setDate({
1035
      ...date,
4134 stevensc 1036
      year: new Intl.DateTimeFormat('es', { year: 'numeric' }).format(value),
1037
      month: new Intl.DateTimeFormat('es', { month: '2-digit' }).format(value),
5195 stevensc 1038
      day: new Intl.DateTimeFormat('es', { day: '2-digit' }).format(value)
4128 stevensc 1039
    })
4143 stevensc 1040
    setTime(new Intl.DateTimeFormat('es', { hour: 'numeric', minute: '2-digit', second: 'numeric' }).format(value))
4128 stevensc 1041
  }
1042
 
4139 stevensc 1043
  const onSubmit = async (data) => {
1044
    try {
1045
      const formData = new FormData()
4134 stevensc 1046
 
4139 stevensc 1047
      Object.entries(data).forEach(([key, value]) => formData.append(key, value))
1048
      formData.append('date', `${date.year}-${date.month}-${date.day}`)
4144 stevensc 1049
      formData.append('time', time)
4139 stevensc 1050
 
1051
      const { data: response } = await axios.post(zoomUrl, formData)
1052
 
4140 stevensc 1053
      if (!response.success && typeof response.data === 'string') {
1054
        dispatch(addNotification({ msg: response.data, style: 'danger' }))
1055
        return
4139 stevensc 1056
      }
1057
 
4140 stevensc 1058
      if (!response.success && typeof response.data === 'object') {
1059
        Object.entries(response.data)
1060
          .forEach(([key, value]) => {
1061
            dispatch(addNotification({ msg: `${key}: ${value[0]}`, style: 'danger' }))
1062
          })
1063
        return
1064
      }
1065
 
4147 stevensc 1066
      dispatch(addNotification({ msg: response.data, style: 'success' }))
1067
      onCreate()
4139 stevensc 1068
      reset()
1069
    } catch (error) {
1070
      console.log(`Error: ${error.message}`)
4140 stevensc 1071
      return dispatch(addNotification({ msg: 'Ha ocurrido un error', style: 'danger' }))
4139 stevensc 1072
    }
4115 stevensc 1073
  }
1074
 
1075
  return (
5052 stevensc 1076
    <StyleModal title='Crea una conferencia' show={show}>
4145 stevensc 1077
      <form onSubmit={handleSubmit(onSubmit)} autoComplete="new-password">
4128 stevensc 1078
        <div className="form-group">
1079
          <label htmlFor="first_name">Título</label>
1080
          <input
1081
            type="text"
1082
            name="title"
1083
            className="form-control"
4133 stevensc 1084
            maxLength={128}
5195 stevensc 1085
            ref={register({ required: 'Por favor ingrese un título' })}
4128 stevensc 1086
          />
5052 stevensc 1087
          {errors.title && <FormErrorFeedback>{errors.title.message}</FormErrorFeedback>}
4128 stevensc 1088
        </div>
1089
        <div className="form-group">
4133 stevensc 1090
          <label htmlFor="first_name">Descripción</label>
1091
          <input
1092
            type="text"
1093
            name="description"
1094
            className="form-control"
5195 stevensc 1095
            ref={register({ required: 'Por favor ingrese una descripción' })}
4133 stevensc 1096
          />
5052 stevensc 1097
          {errors.description && <FormErrorFeedback>{errors.description.message}</FormErrorFeedback>}
4133 stevensc 1098
        </div>
1099
        <div className="form-group">
4134 stevensc 1100
          <label htmlFor="timezone">Tipo de conferencia</label>
1101
          <select
1102
            name="type"
1103
            className="form-control"
1104
            onChange={({ target }) => handleChange(target.value)}
4137 stevensc 1105
            ref={register}
4134 stevensc 1106
          >
1107
            <option value='i'>
1108
              Inmediata
1109
            </option>
1110
            <option value='s'>
1111
              Programada
1112
            </option>
1113
          </select>
1114
        </div>
1115
        {
1116
          coferenceType === 's' &&
1117
          <div className="form-group">
1118
            <label htmlFor="timezone">Horario</label>
1119
            <Datetime
1120
              dateFormat="DD-MM-YYYY"
5017 stevensc 1121
              onChange={(e) => {
5019 stevensc 1122
                if (e.toDate) {
1123
                  handleDateTime(e.toDate())
5017 stevensc 1124
                }
1125
              }}
4134 stevensc 1126
              inputProps={{ className: 'form-control' }}
4138 stevensc 1127
              initialValue={Date.parse(new Date())}
4134 stevensc 1128
              closeOnSelect
1129
            />
1130
          </div>
1131
        }
1132
        <div className="form-group">
4128 stevensc 1133
          <label htmlFor="timezone">Zona horaria</label>
1134
          <select
1135
            className="form-control"
1136
            name="timezone"
5195 stevensc 1137
            ref={register({ required: 'Por favor elige una Zona horaria' })}
4128 stevensc 1138
          >
1139
            <option value="" hidden>
1140
              Zona horaria
1141
            </option>
1142
            {Object.entries(timezones).map(([key, value]) => (
1143
              <option value={key} key={key}>
1144
                {value}
4116 stevensc 1145
              </option>
4128 stevensc 1146
            ))}
1147
          </select>
1148
          {errors.timezone && <FormErrorFeedback>{errors.timezone.message}</FormErrorFeedback>}
4116 stevensc 1149
        </div>
4133 stevensc 1150
        <div className="form-group">
1151
          <label htmlFor="timezone">Duración</label>
1152
          <select
1153
            className="form-control"
1154
            name="duration"
4137 stevensc 1155
            ref={register}
4133 stevensc 1156
          >
1157
            <option value={5}>5-min</option>
1158
            <option value={10}>10-min</option>
1159
            <option value={15}>15-min</option>
1160
            <option value={20}>20-min</option>
1161
            <option value={25}>25-min</option>
1162
            <option value={30}>30-min</option>
1163
            <option value={35}>35-min</option>
1164
            <option value={40}>40-min</option>
1165
            <option value={45}>45-min</option>
1166
          </select>
1167
        </div>
1168
        <div className="form-group">
1169
          <label htmlFor="first_name">Contraseña de ingreso</label>
1170
          <input
1171
            type="password"
1172
            name="password"
1173
            className="form-control"
4137 stevensc 1174
            ref={register({
5195 stevensc 1175
              required: 'Por favor ingrese una contraseña',
1176
              maxLength: { value: 6, message: 'La contraseña debe tener al menos 6 digitos' }
4137 stevensc 1177
            })}
4133 stevensc 1178
          />
5052 stevensc 1179
          {errors.password && <FormErrorFeedback>{errors.password.message}</FormErrorFeedback>}
4115 stevensc 1180
        </div>
5052 stevensc 1181
        <button className="btn btn-primary" type="submit">
4116 stevensc 1182
          Crear
1183
        </button>
4115 stevensc 1184
      </form>
4133 stevensc 1185
    </StyleModal >
4115 stevensc 1186
  )
1187
}
1188
 
5195 stevensc 1189
export default React.memo(PersonalChat)