Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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