Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 5310 | Rev 5312 | 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">
2577 stevensc 622
                  {
5195 stevensc 623
                    responseMessage &&
624
                    <div className={responseMessage ? 'resp_messages-container active' : 'resp_messages-container'}>
2577 stevensc 625
                      <span>{`Respondiendo a ${responseMessage.user_name}`}</span>
626
                      <p>{responseMessage.m}</p>
627
                    </div>
628
                  }
1 www 629
                  <div className="block-wchat">
630
                    <button
631
                      className="icon ti-clip attachment font-24 btn-attach btn-attach uploadFile"
632
                      id="uploadFile"
633
                      onClick={handleShareFileModalShow}
634
                    ></button>
635
                    <button
636
                      className="icon ti-face-smile font-24 btn-emoji"
637
                      id="toggle-emoji"
638
                      onClick={handleShowEmojiTab}
639
                    ></button>
640
                    <div className="input-container">
641
                      <div className="input-emoji">
642
                        <div
643
                          className="input-placeholder"
5195 stevensc 644
                          style={{ visibility: 'hidden', display: 'none' }}
1 www 645
                        >
5206 stevensc 646
                          {CHAT_LABELS.WRITE_A_MESSAGE}
1 www 647
                        </div>
648
                        <textarea
649
                          className="input chatboxtextarea"
650
                          id="chatboxtextarea"
651
                          name="chattxt"
5195 stevensc 652
                          style={{ resize: 'none', height: '20px' }}
5206 stevensc 653
                          placeholder={CHAT_LABELS.WRITE_A_MESSAGE}
1 www 654
                          onKeyDown={handleChatBoxKeyDown}
655
                          ref={textAreaEl}
3045 stevensc 656
                          onBlur={() => responseMessage && setResponseMessage(null)}
3122 stevensc 657
                          onFocus={() => not_seen_messages && onRead(entity)}
658
                        />
1 www 659
                      </div>
660
                    </div>
661
                  </div>
662
                </div>
5058 stevensc 663
 
664
                <div className="wchat-box-items-overlay-container">
5195 stevensc 665
                  <div className="target-emoji" style={{ display: showEmojiTab ? 'block' : 'none' }} id={`smileyPanel_${id}`}>
5058 stevensc 666
                    <Emojione onClickEmoji={handleClickEmoji} />
1 www 667
                  </div>
668
                </div>
5058 stevensc 669
 
1 www 670
              </div>
671
            </div>
672
          </div>
673
        </div>
674
      </div>
5052 stevensc 675
      <SendFileModal
676
        show={shareFileModalShow}
677
        onHide={() => setShareFileModalShow(false)}
678
        urlUpload={url_upload}
679
      />
4147 stevensc 680
      <ConferenceModal
681
        show={showConferenceModal}
682
        timezones={timezones}
683
        zoomUrl={url_zoom}
4149 stevensc 684
        onCreate={() => {
685
          handleShowOptions()
686
          displayConferenceModal()
687
        }}
4147 stevensc 688
      />
4116 stevensc 689
    </>
5195 stevensc 690
  )
1 www 691
 
692
  const groupChat = (
5206 stevensc 693
    <>
694
      <div className="chatbox active-chat " ref={chatboxEl}>
1 www 695
        <div className="panel personal-chat">
696
          <StyledChatHead>
5195 stevensc 697
            <div className={`panel-heading chatboxhead ${not_seen_messages ? 'notify' : ''}`}>
1 www 698
              <div className="panel-title-group">
699
                <img
700
                  className="chat-image img-circle pull-left"
701
                  height="36"
702
                  width="36"
703
                  src="/images/users-group.png"
704
                  alt="avatar-image"
705
                />
5206 stevensc 706
 
1 www 707
                <div className="header-elements">
708
                  <p>{name}</p>
5206 stevensc 709
 
1 www 710
                  <div className="pull-right options">
5206 stevensc 711
                    <div className="btn-group addUser" />
712
                    <i className="fa fa-gear" onClick={handleShowOptions} />
1 www 713
                  </div>
5206 stevensc 714
                  <div className="btn-group">
715
                    <i className='fa fa-minus-circle' onClick={handleActive} />
716
                  </div>
717
                  <div className="btn-group">
718
                    <i className="fa fa-times-circle" onClick={handleCloseChat} />
719
                  </div>
1 www 720
                </div>
5206 stevensc 721
 
1 www 722
              </div>
723
            </div>
724
          </StyledChatHead>
5206 stevensc 725
 
726
          <div className="panel-body" style={{ display: !minimized ? 'block' : 'none' }}>
5195 stevensc 727
            <StyledShowOptions className={` ${showOptions ? 'show' : 'hide'}`}>
1 www 728
              {optionRender()}
729
            </StyledShowOptions>
730
 
731
            <div
732
              className="chat-conversation"
733
              style={{
5195 stevensc 734
                display: showOptions ? 'none' : 'block',
735
                position: 'relative'
1 www 736
              }}
737
            >
738
              <div className="reverseChatBox" ref={conversationListEl}>
739
                <ul
740
                  className="conversation-list chatboxcontent"
741
                  id="resultchat_'+chatboxtitle+'"
742
                >
743
                  {messagesRender()}
744
                </ul>
745
              </div>
3604 stevensc 746
              <div className="wchat-footer wchat-chat-footer">
1 www 747
                <div id="chatFrom">
748
                  <div className="block-wchat">
749
                    <button
750
                      className="icon ti-clip attachment font-24 btn-attach btn-attach uploadFile"
751
                      id="uploadFile"
752
                      onClick={handleShareFileModalShow}
753
                    ></button>
754
                    <button
755
                      className="icon ti-face-smile font-24 btn-emoji"
756
                      id="toggle-emoji"
757
                      onClick={handleShowEmojiTab}
758
                    ></button>
759
                    <div className="input-container">
760
                      <div className="input-emoji">
761
                        <div
762
                          className="input-placeholder"
5195 stevensc 763
                          style={{ visibility: 'hidden', display: 'none' }}
1 www 764
                        >
5206 stevensc 765
                          {CHAT_LABELS.WRITE_A_MESSAGE}
1 www 766
                        </div>
767
                        <textarea
768
                          className="input chatboxtextarea"
769
                          name="chattxt"
5195 stevensc 770
                          style={{ resize: 'none', height: '20px' }}
5206 stevensc 771
                          placeholder={CHAT_LABELS.WRITE_A_MESSAGE}
1 www 772
                          onKeyDown={handleChatBoxKeyDown}
773
                          ref={textAreaEl}
3122 stevensc 774
                          onFocus={() => not_seen_messages && onRead(entity)}
3045 stevensc 775
                          onBlur={() => responseMessage && setResponseMessage(null)}
5206 stevensc 776
                        />
1 www 777
                        <input
778
                          id="to_uname"
779
                          name="to_uname"
780
                          value="'+chatboxtitle+'"
781
                          type="hidden"
782
                        />
783
                        <input
784
                          id="from_uname"
785
                          name="from_uname"
786
                          value="Beenny"
787
                          type="hidden"
788
                        />
789
                      </div>
790
                    </div>
791
                  </div>
792
                </div>
793
                <div className="wchat-box-items-positioning-container">
794
                  <div className="wchat-box-items-overlay-container">
795
                    <div
796
                      className="target-emoji"
5195 stevensc 797
                      style={{ display: showEmojiTab ? 'block' : 'none' }}
1 www 798
                    >
799
                      <div id={`smileyPanel_${id}`}>
800
                        <div>
801
                          <Emojione onClickEmoji={handleClickEmoji} />
802
                        </div>
803
                      </div>
804
                    </div>
805
                  </div>
806
                </div>
807
              </div>
808
            </div>
809
          </div>
810
        </div>
811
      </div>
812
      <ConfirmModal
813
        show={confirmModalShow}
814
        onClose={handleConfirmModalShow}
815
        onAccept={handleConfirmModalAccept}
816
      />
4152 stevensc 817
      <ConferenceModal
818
        show={showConferenceModal}
819
        timezones={timezones}
820
        zoomUrl={url_zoom}
821
        onCreate={() => {
822
          handleShowOptions()
823
          displayConferenceModal()
824
        }}
825
      />
5052 stevensc 826
      <SendFileModal
827
        show={shareFileModalShow}
828
        onHide={() => setShareFileModalShow(false)}
829
        urlUpload={url_upload}
830
      />
5206 stevensc 831
    </>
5195 stevensc 832
  )
1 www 833
 
834
  switch (type) {
5195 stevensc 835
    case 'user':
836
      return userChat
837
    case 'group':
838
      return groupChat
1 www 839
    default:
5195 stevensc 840
      break
1 www 841
  }
5195 stevensc 842
}
1 www 843
 
4115 stevensc 844
const StyleModal = ({
845
  title = 'Crea una conferencia',
846
  size = 'md',
847
  show = false,
848
  children
849
}) => {
850
  const [isShow, setIsShow] = useState(show)
851
 
4118 stevensc 852
  useEffect(() => {
853
    setIsShow(show)
854
  }, [show])
855
 
4115 stevensc 856
  const closeModal = () => setIsShow(false)
857
 
858
  return (
859
    <Modal
860
      show={isShow}
861
      onHide={closeModal}
5195 stevensc 862
      style={{ overflowY: 'scroll' }}
4115 stevensc 863
    >
864
      <Modal.Header closeButton>
865
        <Modal.Title>{title}</Modal.Title>
866
      </Modal.Header>
867
      <Modal.Body>
868
        {children}
869
      </Modal.Body>
870
    </Modal>
871
  )
872
}
873
 
5021 stevensc 874
export const ConferenceModal = ({
4128 stevensc 875
  show = false,
4134 stevensc 876
  timezones = {},
4147 stevensc 877
  zoomUrl = '',
878
  onCreate = () => null
4115 stevensc 879
}) => {
4130 stevensc 880
  const dt = new Date()
4136 stevensc 881
  const { handleSubmit, register, errors, reset } = useForm({ mode: 'all' })
4128 stevensc 882
  const [date, setDate] = useState({
5195 stevensc 883
    year: dt.toLocaleString('default', { year: 'numeric' }),
884
    month: dt.toLocaleString('default', { month: '2-digit' }),
885
    day: dt.toLocaleString('default', { day: '2-digit' })
4128 stevensc 886
  })
5195 stevensc 887
  const [time, setTime] = useState(dt.toLocaleString('es', { hour: 'numeric', minute: '2-digit', second: '2-digit' }))
4120 stevensc 888
  const [coferenceType, setConferenceType] = useState(1)
4140 stevensc 889
  const dispatch = useDispatch()
4115 stevensc 890
 
4120 stevensc 891
  const handleChange = (value) => setConferenceType(value)
892
 
4128 stevensc 893
  const handleDateTime = (value) => {
894
    setDate({
895
      ...date,
4134 stevensc 896
      year: new Intl.DateTimeFormat('es', { year: 'numeric' }).format(value),
897
      month: new Intl.DateTimeFormat('es', { month: '2-digit' }).format(value),
5195 stevensc 898
      day: new Intl.DateTimeFormat('es', { day: '2-digit' }).format(value)
4128 stevensc 899
    })
4143 stevensc 900
    setTime(new Intl.DateTimeFormat('es', { hour: 'numeric', minute: '2-digit', second: 'numeric' }).format(value))
4128 stevensc 901
  }
902
 
4139 stevensc 903
  const onSubmit = async (data) => {
904
    try {
905
      const formData = new FormData()
4134 stevensc 906
 
4139 stevensc 907
      Object.entries(data).forEach(([key, value]) => formData.append(key, value))
908
      formData.append('date', `${date.year}-${date.month}-${date.day}`)
4144 stevensc 909
      formData.append('time', time)
4139 stevensc 910
 
911
      const { data: response } = await axios.post(zoomUrl, formData)
912
 
4140 stevensc 913
      if (!response.success && typeof response.data === 'string') {
914
        dispatch(addNotification({ msg: response.data, style: 'danger' }))
915
        return
4139 stevensc 916
      }
917
 
4140 stevensc 918
      if (!response.success && typeof response.data === 'object') {
919
        Object.entries(response.data)
920
          .forEach(([key, value]) => {
921
            dispatch(addNotification({ msg: `${key}: ${value[0]}`, style: 'danger' }))
922
          })
923
        return
924
      }
925
 
4147 stevensc 926
      dispatch(addNotification({ msg: response.data, style: 'success' }))
927
      onCreate()
4139 stevensc 928
      reset()
929
    } catch (error) {
930
      console.log(`Error: ${error.message}`)
4140 stevensc 931
      return dispatch(addNotification({ msg: 'Ha ocurrido un error', style: 'danger' }))
4139 stevensc 932
    }
4115 stevensc 933
  }
934
 
935
  return (
5052 stevensc 936
    <StyleModal title='Crea una conferencia' show={show}>
4145 stevensc 937
      <form onSubmit={handleSubmit(onSubmit)} autoComplete="new-password">
4128 stevensc 938
        <div className="form-group">
939
          <label htmlFor="first_name">Título</label>
940
          <input
941
            type="text"
942
            name="title"
943
            className="form-control"
4133 stevensc 944
            maxLength={128}
5195 stevensc 945
            ref={register({ required: 'Por favor ingrese un título' })}
4128 stevensc 946
          />
5052 stevensc 947
          {errors.title && <FormErrorFeedback>{errors.title.message}</FormErrorFeedback>}
4128 stevensc 948
        </div>
949
        <div className="form-group">
4133 stevensc 950
          <label htmlFor="first_name">Descripción</label>
951
          <input
952
            type="text"
953
            name="description"
954
            className="form-control"
5195 stevensc 955
            ref={register({ required: 'Por favor ingrese una descripción' })}
4133 stevensc 956
          />
5052 stevensc 957
          {errors.description && <FormErrorFeedback>{errors.description.message}</FormErrorFeedback>}
4133 stevensc 958
        </div>
959
        <div className="form-group">
4134 stevensc 960
          <label htmlFor="timezone">Tipo de conferencia</label>
961
          <select
962
            name="type"
963
            className="form-control"
964
            onChange={({ target }) => handleChange(target.value)}
4137 stevensc 965
            ref={register}
4134 stevensc 966
          >
967
            <option value='i'>
968
              Inmediata
969
            </option>
970
            <option value='s'>
971
              Programada
972
            </option>
973
          </select>
974
        </div>
975
        {
976
          coferenceType === 's' &&
977
          <div className="form-group">
978
            <label htmlFor="timezone">Horario</label>
979
            <Datetime
980
              dateFormat="DD-MM-YYYY"
5017 stevensc 981
              onChange={(e) => {
5019 stevensc 982
                if (e.toDate) {
983
                  handleDateTime(e.toDate())
5017 stevensc 984
                }
985
              }}
4134 stevensc 986
              inputProps={{ className: 'form-control' }}
4138 stevensc 987
              initialValue={Date.parse(new Date())}
4134 stevensc 988
              closeOnSelect
989
            />
990
          </div>
991
        }
992
        <div className="form-group">
4128 stevensc 993
          <label htmlFor="timezone">Zona horaria</label>
994
          <select
995
            className="form-control"
996
            name="timezone"
5195 stevensc 997
            ref={register({ required: 'Por favor elige una Zona horaria' })}
4128 stevensc 998
          >
999
            <option value="" hidden>
1000
              Zona horaria
1001
            </option>
1002
            {Object.entries(timezones).map(([key, value]) => (
1003
              <option value={key} key={key}>
1004
                {value}
4116 stevensc 1005
              </option>
4128 stevensc 1006
            ))}
1007
          </select>
1008
          {errors.timezone && <FormErrorFeedback>{errors.timezone.message}</FormErrorFeedback>}
4116 stevensc 1009
        </div>
4133 stevensc 1010
        <div className="form-group">
1011
          <label htmlFor="timezone">Duración</label>
1012
          <select
1013
            className="form-control"
1014
            name="duration"
4137 stevensc 1015
            ref={register}
4133 stevensc 1016
          >
1017
            <option value={5}>5-min</option>
1018
            <option value={10}>10-min</option>
1019
            <option value={15}>15-min</option>
1020
            <option value={20}>20-min</option>
1021
            <option value={25}>25-min</option>
1022
            <option value={30}>30-min</option>
1023
            <option value={35}>35-min</option>
1024
            <option value={40}>40-min</option>
1025
            <option value={45}>45-min</option>
1026
          </select>
1027
        </div>
1028
        <div className="form-group">
1029
          <label htmlFor="first_name">Contraseña de ingreso</label>
1030
          <input
1031
            type="password"
1032
            name="password"
1033
            className="form-control"
4137 stevensc 1034
            ref={register({
5195 stevensc 1035
              required: 'Por favor ingrese una contraseña',
1036
              maxLength: { value: 6, message: 'La contraseña debe tener al menos 6 digitos' }
4137 stevensc 1037
            })}
4133 stevensc 1038
          />
5052 stevensc 1039
          {errors.password && <FormErrorFeedback>{errors.password.message}</FormErrorFeedback>}
4115 stevensc 1040
        </div>
5052 stevensc 1041
        <button className="btn btn-primary" type="submit">
4116 stevensc 1042
          Crear
1043
        </button>
4115 stevensc 1044
      </form>
5206 stevensc 1045
    </StyleModal>
4115 stevensc 1046
  )
1047
}
1048
 
5195 stevensc 1049
export default React.memo(PersonalChat)