Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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