Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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

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