Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

Rev 5019 | Rev 5026 | 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 shareFileModal = (
626
    <SendFileModal
627
      show={shareFileModalShow}
628
      onHide={() => {
629
        setShareFileModalShow(false);
630
      }}
631
      urlUpload={url_upload}
632
    />
633
  );
634
 
635
  const userChat = (
4116 stevensc 636
    <>
3752 stevensc 637
      <div className="chatbox active-chat" style={{ display: 'block' }}>
1 www 638
        <div className="chatbox-icon">
639
          <div className="contact-floating red">
640
            <img className="chat-image img-circle pull-left" src={image} />
641
            <small className="unread-msg">2</small>
642
          </div>
643
        </div>
644
        <div className="panel personal-chat">
645
          <StyledChatHead>
3094 stevensc 646
            <div className={`panel-heading chatboxhead ${not_seen_messages ? "notify" : ""}`}>
1 www 647
              <div className="panel-title">
648
                <img
649
                  className="chat-image img-circle pull-left"
650
                  height="36"
651
                  width="36"
652
                  src={image}
653
                  alt="avatar-image"
654
                />
655
                <div className="header-elements">
3056 stevensc 656
                  <a href={profile} target="_blank" rel="noreferrer">
1 www 657
                    {name}
658
                  </a>
659
                  <br />
1188 stevensc 660
                  <small className={`status ${online ? "Online" : "Offline"}`}>
661
                    <b>{online ? "En línea" : "Desconectado"}</b>
1 www 662
                  </small>
663
                  <div className="pull-right options">
4115 stevensc 664
                    <div className="btn-group uploadFile">
1 www 665
                      {/* <span>
666
                      <i className="fa fa-trash"></i>
667
                    </span> */}
668
                    </div>
4115 stevensc 669
                    <div className="btn-group">
1 www 670
                      {/* <span>
671
                      <i className="fa fa-trash"></i>
672
                    </span> */}
673
                    </div>
4117 stevensc 674
                    <div className="btn-group">
1 www 675
                      <span>
4154 stevensc 676
                        <i className="fa fa-gear" onClick={() => {
4116 stevensc 677
                          handleChangeTab(optionTabs.meet)
678
                          handleShowOptions()
4117 stevensc 679
                        }}
680
                        />
1 www 681
                      </span>
682
                    </div>
4115 stevensc 683
                    <div className="btn-group">
1 www 684
                      <span>
4115 stevensc 685
                        <i className={`fa fa-minus-circle`} onClick={handleActive} />
1 www 686
                      </span>
687
                    </div>
4115 stevensc 688
                    <div className="btn-group">
689
                      <span>
690
                        <i className="fa fa-times-circle" onClick={handleCloseChat} />
691
                      </span>
692
                    </div>
1 www 693
                  </div>
694
                </div>
695
              </div>
696
            </div>
697
          </StyledChatHead>
698
          <div
699
            className="panel-body"
700
            style={{ display: !minimized ? "block" : "none" }}
701
          >
4116 stevensc 702
            <StyledShowOptions className={` ${showOptions ? "show" : "hide"}`}>
703
              {optionRender()}
704
            </StyledShowOptions>
1 www 705
            <div
706
              id="uploader_'+chatboxtitle+'"
707
              style={{ display: "none", height: "342px" }}
708
            >
709
              <p>
710
                Your browser does not have Flash, Silverlight or HTML5 support.
711
              </p>
712
            </div>
4116 stevensc 713
            <div
714
              className="chat-conversation"
4118 stevensc 715
              style={{ position: "relative", display: showOptions ? 'none' : 'block' }}
4116 stevensc 716
            >
1 www 717
              <div className="reverseChatBox" ref={conversationListEl}>
718
                <ul
719
                  className="conversation-list chatboxcontent"
720
                  id="resultchat_'+chatboxtitle+'"
721
                >
722
                  {messagesRender()}
723
                </ul>
724
              </div>
3604 stevensc 725
              <div className="wchat-footer wchat-chat-footer">
1301 stevensc 726
                <div id="chatFrom" className="chatFrom">
2577 stevensc 727
                  {
728
                    responseMessage
729
                    &&
730
                    <div className={responseMessage ? "resp_messages-container active" : "resp_messages-container"}>
731
                      <span>{`Respondiendo a ${responseMessage.user_name}`}</span>
732
                      <p>{responseMessage.m}</p>
733
                    </div>
734
                  }
1 www 735
                  <div className="block-wchat">
736
                    <button
737
                      className="icon ti-clip attachment font-24 btn-attach btn-attach uploadFile"
738
                      id="uploadFile"
739
                      onClick={handleShareFileModalShow}
740
                    ></button>
741
                    <button
742
                      className="icon ti-face-smile font-24 btn-emoji"
743
                      id="toggle-emoji"
744
                      onClick={handleShowEmojiTab}
745
                    ></button>
746
                    <div className="input-container">
747
                      <div className="input-emoji">
748
                        <div
749
                          className="input-placeholder"
750
                          style={{ visibility: "hidden", display: "none" }}
751
                        >
752
                          Escribe un mensaje
753
                        </div>
754
                        <textarea
755
                          className="input chatboxtextarea"
756
                          id="chatboxtextarea"
757
                          name="chattxt"
758
                          style={{ resize: "none", height: "20px" }}
759
                          placeholder="Escribe un mensaje"
760
                          onKeyDown={handleChatBoxKeyDown}
761
                          ref={textAreaEl}
3045 stevensc 762
                          onBlur={() => responseMessage && setResponseMessage(null)}
3122 stevensc 763
                          onFocus={() => not_seen_messages && onRead(entity)}
764
                        />
1 www 765
                        <input
766
                          id="to_uname"
767
                          name="to_uname"
768
                          value="'+chatboxtitle+'"
769
                          type="hidden"
770
                        />
771
                        <input
772
                          id="from_uname"
773
                          name="from_uname"
774
                          value="Beenny"
775
                          type="hidden"
776
                        />
777
                      </div>
778
                    </div>
779
                  </div>
780
                </div>
781
                <div className="wchat-box-items-positioning-container">
782
                  <div className="wchat-box-items-overlay-container">
783
                    <div
784
                      className="target-emoji"
785
                      style={{ display: showEmojiTab ? "block" : "none" }}
786
                    >
787
                      <div id={`smileyPanel_${id}`}>
788
                        <div>
789
                          <Emojione onClickEmoji={handleClickEmoji} />
790
                        </div>
791
                      </div>
792
                    </div>
793
                  </div>
794
                </div>
795
              </div>
796
            </div>
797
          </div>
798
        </div>
799
      </div>
800
      {shareFileModal}
4147 stevensc 801
      <ConferenceModal
802
        show={showConferenceModal}
803
        timezones={timezones}
804
        zoomUrl={url_zoom}
4149 stevensc 805
        onCreate={() => {
806
          handleShowOptions()
807
          displayConferenceModal()
808
        }}
4147 stevensc 809
      />
4116 stevensc 810
    </>
1 www 811
  );
812
 
813
  const groupChat = (
814
    <React.Fragment>
815
      <div
3752 stevensc 816
        className="chatbox active-chat "
1 www 817
        ref={chatboxEl}
818
      >
819
        <div className="chatbox-icon">
820
          <div className="contact-floating red">
821
            <img className="chat-image img-circle pull-left" src={image} />
822
            <small className="unread-msg">2</small>
823
          </div>
824
        </div>
825
        <div className="panel personal-chat">
826
          <StyledChatHead>
3752 stevensc 827
            <div className={`panel-heading chatboxhead ${not_seen_messages ? "notify" : ""}`}>
1 www 828
              <div className="panel-title-group">
829
                <img
830
                  className="chat-image img-circle pull-left"
831
                  height="36"
832
                  width="36"
833
                  src="/images/users-group.png"
834
                  alt="avatar-image"
835
                />
836
                <div className="header-elements">
837
                  <p>{name}</p>
838
                  <br />
839
                  <div className="pull-right options">
840
                    <div
841
                      className="btn-group uploadFile"
842
                      id="uploadFile"
843
                      data-client="'+chatboxtitle+'"
844
                    >
845
                    </div>
3752 stevensc 846
                    <div className="btn-group">
1 www 847
                    </div>
848
                    <div
849
                      className="btn-group addUser"
850
                      data-client="8cb2a840-56c2-4f93-9cf1-27ad598acd8f"
851
                      data-name="Grupo de jesus"
852
                    >
853
                      <span>
854
                        <i
855
                          className="fa fa-gear"
856
                          onClick={handleShowOptions}
857
                        ></i>
858
                      </span>
859
                    </div>
3752 stevensc 860
                    <div className="btn-group">
1 www 861
                      <span>
862
                        <i
863
                          className={`fa fa-minus-circle`}
864
                          onClick={handleActive}
865
                        ></i>
866
                      </span>
867
                    </div>
3752 stevensc 868
                    <div className="btn-group">
1 www 869
                      <span>
870
                        <i
871
                          className="fa fa-times-circle"
872
                          onClick={handleCloseChat}
873
                        ></i>
874
                      </span>
875
                    </div>
876
                  </div>
877
                </div>
878
              </div>
879
            </div>
880
          </StyledChatHead>
881
          <div
882
            className="panel-body"
883
            style={{ display: !minimized ? "block" : "none" }}
884
          >
885
            <StyledShowOptions className={` ${showOptions ? "show" : "hide"}`}>
886
              {optionRender()}
887
            </StyledShowOptions>
888
 
889
            <div
890
              className="chat-conversation"
891
              style={{
892
                display: showOptions ? "none" : "block",
893
                position: "relative",
894
              }}
895
            >
896
              <div className="reverseChatBox" ref={conversationListEl}>
897
                <ul
898
                  className="conversation-list chatboxcontent"
899
                  id="resultchat_'+chatboxtitle+'"
900
                >
901
                  {messagesRender()}
902
                </ul>
903
              </div>
3604 stevensc 904
              <div className="wchat-footer wchat-chat-footer">
1 www 905
                <div id="chatFrom">
906
                  <div className="block-wchat">
907
                    <button
908
                      className="icon ti-clip attachment font-24 btn-attach btn-attach uploadFile"
909
                      id="uploadFile"
910
                      onClick={handleShareFileModalShow}
911
                    ></button>
912
                    <button
913
                      className="icon ti-face-smile font-24 btn-emoji"
914
                      id="toggle-emoji"
915
                      onClick={handleShowEmojiTab}
916
                    ></button>
917
                    <div className="input-container">
918
                      <div className="input-emoji">
919
                        <div
920
                          className="input-placeholder"
921
                          style={{ visibility: "hidden", display: "none" }}
922
                        >
923
                          Escribe un mensaje
924
                        </div>
925
                        <textarea
926
                          className="input chatboxtextarea"
927
                          id="chatboxtextarea"
928
                          name="chattxt"
929
                          style={{ resize: "none", height: "20px" }}
930
                          placeholder="Escribe un mensaje"
931
                          onKeyDown={handleChatBoxKeyDown}
932
                          ref={textAreaEl}
3122 stevensc 933
                          onFocus={() => not_seen_messages && onRead(entity)}
3045 stevensc 934
                          onBlur={() => responseMessage && setResponseMessage(null)}
1 www 935
                        ></textarea>
936
                        <input
937
                          id="to_uname"
938
                          name="to_uname"
939
                          value="'+chatboxtitle+'"
940
                          type="hidden"
941
                        />
942
                        <input
943
                          id="from_uname"
944
                          name="from_uname"
945
                          value="Beenny"
946
                          type="hidden"
947
                        />
948
                      </div>
949
                    </div>
950
                  </div>
951
                </div>
952
                <div className="wchat-box-items-positioning-container">
953
                  <div className="wchat-box-items-overlay-container">
954
                    <div
955
                      className="target-emoji"
956
                      style={{ display: showEmojiTab ? "block" : "none" }}
957
                    >
958
                      <div id={`smileyPanel_${id}`}>
959
                        <div>
960
                          <Emojione onClickEmoji={handleClickEmoji} />
961
                        </div>
962
                      </div>
963
                    </div>
964
                  </div>
965
                </div>
966
              </div>
967
            </div>
968
          </div>
969
        </div>
970
      </div>
971
      <ConfirmModal
972
        show={confirmModalShow}
973
        onClose={handleConfirmModalShow}
974
        onAccept={handleConfirmModalAccept}
975
      />
4152 stevensc 976
      <ConferenceModal
977
        show={showConferenceModal}
978
        timezones={timezones}
979
        zoomUrl={url_zoom}
980
        onCreate={() => {
981
          handleShowOptions()
982
          displayConferenceModal()
983
        }}
984
      />
1 www 985
      {shareFileModal}
986
    </React.Fragment>
987
  );
988
 
989
  switch (type) {
990
    case "user":
991
      return userChat;
992
    case "group":
993
      return groupChat;
994
    default:
995
      break;
996
  }
997
};
998
 
4115 stevensc 999
const StyleModal = ({
1000
  title = 'Crea una conferencia',
1001
  size = 'md',
1002
  show = false,
1003
  children
1004
}) => {
1005
 
1006
  const [isShow, setIsShow] = useState(show)
1007
 
4118 stevensc 1008
  useEffect(() => {
1009
    setIsShow(show)
1010
  }, [show])
1011
 
4115 stevensc 1012
  const closeModal = () => setIsShow(false)
1013
 
1014
  return (
1015
    <Modal
1016
      size={size}
1017
      show={isShow}
1018
      onHide={closeModal}
1019
      style={{ overflowY: "scroll" }}
1020
    >
1021
      <Modal.Header closeButton>
1022
        <Modal.Title>{title}</Modal.Title>
1023
      </Modal.Header>
1024
      <Modal.Body>
1025
        {children}
1026
      </Modal.Body>
1027
    </Modal>
1028
  )
1029
}
1030
 
5021 stevensc 1031
export const ConferenceModal = ({
4128 stevensc 1032
  show = false,
4134 stevensc 1033
  timezones = {},
4147 stevensc 1034
  zoomUrl = '',
1035
  onCreate = () => null
4115 stevensc 1036
}) => {
1037
 
4130 stevensc 1038
  const dt = new Date()
4136 stevensc 1039
  const { handleSubmit, register, errors, reset } = useForm({ mode: 'all' })
4128 stevensc 1040
  const [date, setDate] = useState({
4130 stevensc 1041
    year: dt.toLocaleString("default", { year: "numeric" }),
1042
    month: dt.toLocaleString("default", { month: "2-digit" }),
1043
    day: dt.toLocaleString("default", { day: "2-digit" })
4128 stevensc 1044
  })
4145 stevensc 1045
  const [time, setTime] = useState(dt.toLocaleString("es", { hour: 'numeric', minute: '2-digit', second: '2-digit' }))
4120 stevensc 1046
  const [coferenceType, setConferenceType] = useState(1)
4140 stevensc 1047
  const dispatch = useDispatch()
4115 stevensc 1048
 
4120 stevensc 1049
  const handleChange = (value) => setConferenceType(value)
1050
 
4128 stevensc 1051
  const handleDateTime = (value) => {
1052
    setDate({
1053
      ...date,
4134 stevensc 1054
      year: new Intl.DateTimeFormat('es', { year: 'numeric' }).format(value),
1055
      month: new Intl.DateTimeFormat('es', { month: '2-digit' }).format(value),
1056
      day: new Intl.DateTimeFormat('es', { day: '2-digit' }).format(value),
4128 stevensc 1057
    })
4143 stevensc 1058
    setTime(new Intl.DateTimeFormat('es', { hour: 'numeric', minute: '2-digit', second: 'numeric' }).format(value))
4128 stevensc 1059
  }
1060
 
4139 stevensc 1061
  const onSubmit = async (data) => {
1062
    try {
1063
      const formData = new FormData()
4134 stevensc 1064
 
4139 stevensc 1065
      Object.entries(data).forEach(([key, value]) => formData.append(key, value))
1066
      formData.append('date', `${date.year}-${date.month}-${date.day}`)
4144 stevensc 1067
      formData.append('time', time)
4139 stevensc 1068
 
1069
      const { data: response } = await axios.post(zoomUrl, formData)
1070
 
4140 stevensc 1071
      if (!response.success && typeof response.data === 'string') {
1072
        dispatch(addNotification({ msg: response.data, style: 'danger' }))
1073
        return
4139 stevensc 1074
      }
1075
 
4140 stevensc 1076
      if (!response.success && typeof response.data === 'object') {
1077
        Object.entries(response.data)
1078
          .forEach(([key, value]) => {
1079
            dispatch(addNotification({ msg: `${key}: ${value[0]}`, style: 'danger' }))
1080
          })
1081
        return
1082
      }
1083
 
4147 stevensc 1084
      dispatch(addNotification({ msg: response.data, style: 'success' }))
1085
      onCreate()
4139 stevensc 1086
      reset()
1087
    } catch (error) {
1088
      console.log(`Error: ${error.message}`)
4140 stevensc 1089
      return dispatch(addNotification({ msg: 'Ha ocurrido un error', style: 'danger' }))
4139 stevensc 1090
    }
4115 stevensc 1091
  }
1092
 
1093
  return (
1094
    <StyleModal
1095
      title='Crea una conferencia'
1096
      size='md'
1097
      show={show}
1098
    >
4145 stevensc 1099
      <form onSubmit={handleSubmit(onSubmit)} autoComplete="new-password">
4128 stevensc 1100
        <div className="form-group">
1101
          <label htmlFor="first_name">Título</label>
1102
          <input
1103
            type="text"
1104
            name="title"
1105
            className="form-control"
4133 stevensc 1106
            maxLength={128}
4137 stevensc 1107
            ref={register({ required: "Por favor ingrese un título" })}
4128 stevensc 1108
          />
1109
          {errors.title && <FormErrorFeedback> {errors.title.message}</FormErrorFeedback>}
1110
        </div>
1111
        <div className="form-group">
4133 stevensc 1112
          <label htmlFor="first_name">Descripción</label>
1113
          <input
1114
            type="text"
1115
            name="description"
1116
            className="form-control"
4137 stevensc 1117
            ref={register({ required: "Por favor ingrese una descripción" })}
4133 stevensc 1118
          />
4138 stevensc 1119
          {errors.description && <FormErrorFeedback> {errors.description.message}</FormErrorFeedback>}
4133 stevensc 1120
        </div>
1121
        <div className="form-group">
4134 stevensc 1122
          <label htmlFor="timezone">Tipo de conferencia</label>
1123
          <select
1124
            name="type"
1125
            className="form-control"
1126
            onChange={({ target }) => handleChange(target.value)}
4137 stevensc 1127
            ref={register}
4134 stevensc 1128
          >
1129
            <option value='i'>
1130
              Inmediata
1131
            </option>
1132
            <option value='s'>
1133
              Programada
1134
            </option>
1135
          </select>
1136
        </div>
1137
        {
1138
          coferenceType === 's' &&
1139
          <div className="form-group">
1140
            <label htmlFor="timezone">Horario</label>
1141
            <Datetime
1142
              dateFormat="DD-MM-YYYY"
5017 stevensc 1143
              onChange={(e) => {
5019 stevensc 1144
                if (e.toDate) {
1145
                  handleDateTime(e.toDate())
5017 stevensc 1146
                }
1147
              }}
4134 stevensc 1148
              inputProps={{ className: 'form-control' }}
4138 stevensc 1149
              initialValue={Date.parse(new Date())}
4134 stevensc 1150
              closeOnSelect
1151
            />
1152
          </div>
1153
        }
1154
        <div className="form-group">
4128 stevensc 1155
          <label htmlFor="timezone">Zona horaria</label>
1156
          <select
1157
            className="form-control"
1158
            name="timezone"
4137 stevensc 1159
            ref={register({ required: "Por favor elige una Zona horaria" })}
4128 stevensc 1160
          >
1161
            <option value="" hidden>
1162
              Zona horaria
1163
            </option>
1164
            {Object.entries(timezones).map(([key, value]) => (
1165
              <option value={key} key={key}>
1166
                {value}
4116 stevensc 1167
              </option>
4128 stevensc 1168
            ))}
1169
          </select>
1170
          {errors.timezone && <FormErrorFeedback>{errors.timezone.message}</FormErrorFeedback>}
4116 stevensc 1171
        </div>
4133 stevensc 1172
        <div className="form-group">
1173
          <label htmlFor="timezone">Duración</label>
1174
          <select
1175
            className="form-control"
1176
            name="duration"
4137 stevensc 1177
            ref={register}
4133 stevensc 1178
          >
1179
            <option value={5}>5-min</option>
1180
            <option value={10}>10-min</option>
1181
            <option value={15}>15-min</option>
1182
            <option value={20}>20-min</option>
1183
            <option value={25}>25-min</option>
1184
            <option value={30}>30-min</option>
1185
            <option value={35}>35-min</option>
1186
            <option value={40}>40-min</option>
1187
            <option value={45}>45-min</option>
1188
          </select>
1189
        </div>
1190
        <div className="form-group">
1191
          <label htmlFor="first_name">Contraseña de ingreso</label>
1192
          <input
1193
            type="password"
1194
            name="password"
1195
            className="form-control"
4137 stevensc 1196
            ref={register({
1197
              required: "Por favor ingrese una contraseña",
4145 stevensc 1198
              maxLength: { value: 6, message: "La contraseña debe tener al menos 6 digitos" }
4137 stevensc 1199
            })}
4133 stevensc 1200
          />
4139 stevensc 1201
          {errors.password && <FormErrorFeedback> {errors.password.message}</FormErrorFeedback>}
4115 stevensc 1202
        </div>
4136 stevensc 1203
        <button
1204
          className="btn btn-primary"
1205
          type="submit"
1206
        >
4116 stevensc 1207
          Crear
1208
        </button>
4115 stevensc 1209
      </form>
4133 stevensc 1210
    </StyleModal >
4115 stevensc 1211
  )
1212
}
1213
 
1214
export default React.memo(PersonalChat);