Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

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