Proyectos de Subversion LeadersLinked - Antes de SPA

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
4119 stevensc 1
/* eslint-disable react/prop-types */
3101 stevensc 2
import React from "react";
1 www 3
import { useState, useEffect } from "react";
976 stevensc 4
import { axios } from "../../utils";
1 www 5
import Contacts from "./contacts/Contacts";
1335 stevensc 6
import NotificationAlert from "../../shared/notification/NotificationAlert";
1 www 7
import Groups from "./groups/Groups";
8
import PersonalChat from "./personal-chat/PersonalChat";
2739 stevensc 9
import { FiMaximize2 } from 'react-icons/fi'
4858 stevensc 10
import { addNotification } from "../../redux/notification/notification.actions";
11
import { useDispatch } from "react-redux";
12
import { Modal } from "react-bootstrap";
13
import Spinner from "../../shared/loading-spinner/Spinner";
14
import SendIcon from '@mui/icons-material/Send'
4860 stevensc 15
import AddIcon from '@mui/icons-material/Add'
1 www 16
 
17
const notifyAudio = new Audio("/audio/chat.mp3");
18
 
19
const Chat = (props) => {
20
  // states
21
  const [contacts, setContacts] = useState([]);
22
  const [groups, setGroups] = useState([]);
23
  const [activeChats, setActiveChats] = useState([]);
24
  const [isChatOpen, setIsChatOpen] = useState(false);
25
  const [isMuted, setIsMuted] = useState(false);
4866 stevensc 26
  const [showModal, setShowModal] = useState(false);
1 www 27
  const [activeTab, setActiveTab] = useState("user");
976 stevensc 28
  const [search, setSearch] = useState('');
1775 stevensc 29
  const [loading, setLoading] = useState(false);
4868 stevensc 30
  const [pendingConversation, setPendingConversation] = useState('')
4880 stevensc 31
 
32
  const { defaultNetwork } = props
976 stevensc 33
 
994 stevensc 34
  const filtredContacts = contacts.filter(({ name }) => name.toLowerCase().includes(search.toLowerCase()))
35
  const filtredGroups = groups.filter(({ name }) => name.toLowerCase().includes(search.toLowerCase()))
976 stevensc 36
 
37
  const handleEntities = entities => {
687 steven 38
    let newUserContacts = [];
39
    let newGroups = [];
40
    entities.map((entity) => {
3111 stevensc 41
      if (entity.not_received_messages) handleNewMessage(entity)
42
      if (entity.not_seen_messages) handleNotSeenMessage(entity)
3119 stevensc 43
      if (entity.is_open) handleOpenConversation(entity, false);
687 steven 44
      switch (entity.type) {
45
        case "user":
46
          newUserContacts = [...newUserContacts, entity];
47
          handleUpdateOnline(entity);
48
          break;
49
        case "group":
50
          newGroups = [...newGroups, entity];
51
          break;
52
        default:
53
          break;
54
      }
55
    });
56
    setContacts(newUserContacts);
57
    setGroups(newGroups);
58
  }
2790 stevensc 59
 
687 steven 60
  const heartBeat = async () => {
689 steven 61
    try {
3119 stevensc 62
      const { data } = await axios.get("/chat/heart-beat")
63
      if (data.success) {
64
        handleEntities(data.data)
1 www 65
      }
3119 stevensc 66
      return data.data;
689 steven 67
    } catch (error) {
976 stevensc 68
      console.log('>>: chat error > ', error)
689 steven 69
    }
687 steven 70
  };
1 www 71
 
72
  const handleUpdateOnline = (entity) => {
73
    const existingChatId = activeChats.findIndex(
74
      (activeChat) => activeChat.id === entity.id
75
    );
76
    if (existingChatId >= 0) {
77
      if (activeChats[existingChatId].online !== entity.online) {
78
        const newActiveChats = [...activeChats];
79
        newActiveChats[existingChatId].online = entity.online;
80
        setActiveChats(newActiveChats);
81
      }
82
    }
83
  };
84
 
85
  const handleNewMessage = async (unseeEntity) => {
3596 stevensc 86
    await axios.post(unseeEntity.url_mark_received)
1 www 87
    if (!activeChats.some((activeChat) => activeChat.id === unseeEntity.id)) {
88
      setActiveChats([...activeChats, { ...unseeEntity, minimized: false }]);
89
      playNotifyAudio();
90
    } else {
91
      const existingChatId = activeChats.findIndex(
92
        (activeChat) => activeChat.id === unseeEntity.id
93
      );
94
      if (!activeChats[existingChatId].unsee_messages) {
95
        const newActiveChats = [...activeChats];
96
        newActiveChats[existingChatId].unsee_messages = true;
97
        setActiveChats(newActiveChats);
98
        playNotifyAudio(newActiveChats[existingChatId].minimized);
99
      }
100
    }
101
  };
102
 
3122 stevensc 103
  const handleCloseConversation = async (entity) => {
3127 stevensc 104
    const { data } = await axios.post(entity.url_close)
105
    if (!data.success) console.log('Error in entity close')
106
    setActiveChats(activeChats.filter(prevActiveChats => prevActiveChats.id !== entity.id))
3122 stevensc 107
  }
108
 
109
  const handleOpenConversation = async (entity, minimized = false) => {
3129 stevensc 110
    if (activeChats.length < 3 && !activeChats.some((el) => el.id === entity.id)) {
111
      setActiveChats([...activeChats, { ...entity, minimized: minimized }]);
3127 stevensc 112
    }
3129 stevensc 113
    if (activeChats.length >= 3 && !activeChats.some((el) => el.id === entity.id)) {
114
      await handleCloseConversation(activeChats[0])
115
      setActiveChats(prevActiveChats => [...prevActiveChats, { ...entity, minimized: minimized }]);
986 stevensc 116
    }
1 www 117
  };
118
 
3122 stevensc 119
  const handleReadConversation = async (entity) => {
120
    try {
121
      const { data } = await axios.post(entity.url_mark_seen)
122
      if (!data.success) console.log('Ha ocurrido un error')
123
      setActiveChats(prevActiveChats => [...prevActiveChats].map(chat => {
124
        if (entity.id === chat.id) return { ...chat, not_seen_messages: false }
125
        return chat;
126
      }))
127
    } catch (error) {
128
      console.log(`Error: ${error}`)
1 www 129
    }
130
  };
131
 
3123 stevensc 132
  const handleMinimizeConversation = (entity, minimized = null) => {
133
    return setActiveChats(prevActiveChats => [...prevActiveChats].map(chat => {
3130 stevensc 134
      if (entity.id === chat.id) return { ...chat, minimized: minimized ?? !chat.minimized }
3123 stevensc 135
      return chat
136
    }))
137
  }
1 www 138
 
3119 stevensc 139
  const handleNotSeenMessage = (entity) => {
3111 stevensc 140
    const index = activeChats.findIndex(chat => chat.id === entity.id)
141
 
142
    if (index !== -1) {
143
      setActiveChats(prev => [...prev].map(chat => {
144
        if (chat.id === entity.id) {
145
          return {
146
            ...chat,
147
            not_seen_messages: entity.not_seen_messages
148
          }
149
        }
150
        return chat;
151
      }))
152
    }
3119 stevensc 153
 
154
  }
155
 
1 www 156
  const playNotifyAudio = (minimized = true) => {
157
    if (!isMuted && minimized) {
158
      notifyAudio.play();
159
    }
160
  };
161
 
162
  const handleMute = () => {
163
    setIsMuted(!isMuted);
164
    if (isMuted) {
165
      notifyAudio.play();
166
    }
167
  };
168
 
4858 stevensc 169
  const handleChangeTab = (tab) => setActiveTab(tab)
1 www 170
 
171
  useEffect(() => {
2548 stevensc 172
    if (!loading) {
2973 stevensc 173
      const fetchData = async () => {
2966 stevensc 174
        setLoading(true)
2973 stevensc 175
        const entities = await heartBeat() || [];
2966 stevensc 176
        setLoading(false)
2973 stevensc 177
 
178
        return entities
2966 stevensc 179
      }
180
 
2989 stevensc 181
      setTimeout(() => {
182
        fetchData()
183
      }, "2000")
691 steven 184
    }
2965 stevensc 185
  }, [loading]);
978 stevensc 186
 
1 www 187
  useEffect(() => {
4868 stevensc 188
    if (pendingConversation) {
189
      const pendingChat = contacts.find(contact => contact.url_send === pendingConversation)
4872 stevensc 190
 
191
      if (pendingChat) {
192
        handleOpenConversation(pendingChat)
193
        setPendingConversation('')
194
      }
4880 stevensc 195
 
4868 stevensc 196
    }
197
  }, [pendingConversation, contacts])
198
 
199
  useEffect(() => {
1 www 200
    emojione.imageType = "png";
201
    emojione.sprites = false;
202
    emojione.ascii = true;
203
    emojione.imagePathPNG = props.emojiOnePath;
204
  }, []);
205
 
2069 steven 206
  return (window.innerWidth > 1000 && window.location.pathname !== '/chat') ? (
1 www 207
    <React.Fragment>
208
      <div id="drupalchat-wrapper">
209
        <div id="drupalchat">
210
          <div className="item-list" id="chatbox_chatlist">
211
            <ul id="mainpanel">
212
              <li id="chatpanel" className="first last">
2550 stevensc 213
                <div className="subpanel">
1 www 214
                  <div
215
                    className="subpanel_title"
2554 stevensc 216
                    onClick={(e) => (e.currentTarget === e.target) && setIsChatOpen(!isChatOpen)}
1 www 217
                  >
2554 stevensc 218
                    <a
219
                      href="/chat"
3596 stevensc 220
                      className="text-chat-title"
1 www 221
                    >
2554 stevensc 222
                      Chat
2739 stevensc 223
                      <FiMaximize2 className="ml-3" />
2554 stevensc 224
                    </a>
225
                    <div className="subpanel_title-icons">
2555 stevensc 226
                      <i
227
                        className={`icon ${isMuted ? "icon-volume-off" : "icon-volume-2"} text-20`}
228
                        onClick={handleMute}
229
                      />
230
                      <i
231
                        className={`fa ${isChatOpen ? "fa-angle-down" : "fa-angle-up"} text-20`}
232
                        onClick={() => setIsChatOpen(!isChatOpen)}
233
                      />
1 www 234
                    </div>
235
                  </div>
236
                  <div
237
                    id="showhidechatlist"
2551 stevensc 238
                    style={{ display: isChatOpen ? "grid" : "none" }}
1 www 239
                  >
3595 stevensc 240
                    <div className="drupalchat_search_main chatboxinput">
2561 stevensc 241
                      <input
242
                        className="drupalchat_searchinput live-search-box"
243
                        id="live-search-box"
244
                        type="text"
245
                        name='search'
246
                        value={search}
4860 stevensc 247
                        onChange={(e) => setSearch(e.target.value)}
2561 stevensc 248
                      />
249
                      <i className="searchbutton fas fa-search" />
1 www 250
                    </div>
4880 stevensc 251
                    {defaultNetwork !== 'y' &&
252
                      <div
253
                        className="d-flex align-items-center cursor-pointer"
254
                        style={{ gap: '.5rem', background: '#fff' }}
255
                        onClick={() => setShowModal(true)}
256
                      >
257
                        <AddIcon />
258
                        <span>Iniciar conversación</span>
259
                      </div>
260
                    }
4860 stevensc 261
                    <div className="drupalchat_search_main chatboxinput">
2548 stevensc 262
                      <button
2549 stevensc 263
                        className={`${activeTab === 'user' ? 'active' : ''}`}
2548 stevensc 264
                        onClick={() => handleChangeTab("user")}
1 www 265
                      >
2548 stevensc 266
                        Contactos
267
                      </button>
268
                      <button
2549 stevensc 269
                        className={`${activeTab === 'group' ? 'active' : ''}`}
2548 stevensc 270
                        onClick={() => handleChangeTab("group")}
1 www 271
                      >
2548 stevensc 272
                        Grupos
273
                      </button>
1 www 274
                    </div>
275
                    <div
276
                      className="contact-list chatboxcontent"
3596 stevensc 277
                      style={{ display: activeTab === "user" ? "block" : "none", }}
1 www 278
                    >
279
                      <Contacts
976 stevensc 280
                        contacts={filtredContacts}
1 www 281
                        onOpenConversation={handleOpenConversation}
282
                      />
3058 stevensc 283
                    </div>
1 www 284
                    <div
285
                      className="group-list chatboxcontent"
3596 stevensc 286
                      style={{ display: activeTab === "group" ? "block" : "none", }}
1 www 287
                    >
288
                      <ul id="group-list-ul" className="live-search-list-group">
289
                        <Groups
988 stevensc 290
                          groups={filtredGroups}
1 www 291
                          onOpenConversation={handleOpenConversation}
292
                        />
293
                      </ul>
294
                    </div>
295
                    <div
296
                      className="group-contacts-list chatboxcontent"
297
                      style={{ display: "none" }}
298
                    >
299
                      <div style={{ textAlign: "center", fontSize: "13px" }}>
300
                        Integrantes del grupo
301
                      </div>
302
                      <ul
303
                        id="contact-group-list-ul"
304
                        className="live-search-list"
305
                      ></ul>
306
                    </div>
307
                  </div>
308
                </div>
309
              </li>
310
            </ul>
311
          </div>
312
        </div>
313
      </div>
3133 stevensc 314
      <div className="active_chats-list">
1 www 315
        {activeChats.map((entity, index) => (
316
          <PersonalChat
3131 stevensc 317
            index={index}
1 www 318
            key={entity.id}
319
            entity={entity}
3106 stevensc 320
            not_seen_messages={entity.not_seen_messages}
3131 stevensc 321
            minimized={entity.minimized}
3122 stevensc 322
            onClose={handleCloseConversation}
3123 stevensc 323
            onMinimize={handleMinimizeConversation}
3122 stevensc 324
            onRead={handleReadConversation}
4119 stevensc 325
            timezones={props.timezones}
1 www 326
          />
327
        ))}
328
      </div>
4867 stevensc 329
      <Chat.ContactsModal
330
        show={showModal}
4869 stevensc 331
        setConversation={(url) => setPendingConversation(url)}
4866 stevensc 332
      />
1335 stevensc 333
      <NotificationAlert />
4880 stevensc 334
    </React.Fragment >
1 www 335
  ) : (
336
    ""
337
  );
4858 stevensc 338
}
1 www 339
 
4860 stevensc 340
const ContactsModal = ({ show, setConversation }) => {
4858 stevensc 341
  let axiosThrottle = null
342
  const [isShow, setIsShow] = useState(show)
343
  const [searchResult, setSearchResult] = useState({})
344
  const [loading, setLoading] = useState(false)
345
  const dispatch = useDispatch()
346
 
4880 stevensc 347
  const closeModal = () => {
348
    setIsShow(false)
349
    setSearchResult({})
350
  }
4858 stevensc 351
 
352
  const handleSearch = (contact) => {
353
    clearTimeout(axiosThrottle)
354
    axiosThrottle = setTimeout(() => {
355
      fetchContacts(contact)
356
    }, 500);
357
  };
358
 
359
  const fetchContacts = async (searchParam = '') => {
360
    setLoading(true)
361
    await axios
4870 stevensc 362
      .get(`/chat/users?search=${searchParam.toLowerCase()}`)
4858 stevensc 363
      .then(({ data: response }) => {
364
        if (!response.success) return dispatch(addNotification({ style: 'danger', msg: 'Ha ocurrido un error' }))
365
        setSearchResult(response.data)
366
      })
367
      .finally(() => setLoading(false))
368
  }
369
 
370
  const startConversation = async (send_url = '', name = '') => {
4871 stevensc 371
    const formData = new FormData()
372
    const fullName = name.split(' ')
4880 stevensc 373
    formData.append("message", `Hola, ${fullName[0]}`)
4858 stevensc 374
 
375
    setLoading(true)
376
    await axios
4867 stevensc 377
      .post(send_url, formData)
4858 stevensc 378
      .then(({ data: response }) => {
4868 stevensc 379
        if (response.success) {
380
          setConversation(send_url)
381
          closeModal()
382
        }
4858 stevensc 383
      })
384
      .finally(() => setLoading(false))
385
  }
386
 
387
  useEffect(() => {
388
    setIsShow(show)
389
  }, [show])
390
 
391
  return (
392
    <Modal
393
      show={isShow}
394
      onHide={closeModal}
395
    >
396
      <Modal.Header closeButton>
4868 stevensc 397
        <h3 className="card-title font-weight-bold">Iniciar conversación</h3>
4858 stevensc 398
      </Modal.Header>
399
      <div className="form-group">
400
        <label htmlFor="search-people">Escribe el nombre</label>
401
        <input
402
          type="text"
403
          className="form-control"
404
          placeholder="Escribe el nombre de la persona"
405
          onChange={(e) => handleSearch(e.target.value)}
406
        />
407
      </div>
408
      <div className='container'>
409
        {loading
410
          ? <Spinner />
411
          : Object.entries(searchResult).map(([key, value]) => {
412
            return (
413
              <div className='row' key={key}>
414
                <div className='col-8'>
415
                  <p>{value}</p>
416
                </div>
417
                <div className='col-4'>
418
                  <button
419
                    className='btn btn-primary'
4867 stevensc 420
                    onClick={() => startConversation(key, value)}
4858 stevensc 421
                  >
422
                    <SendIcon />
423
                  </button>
424
                </div>
425
              </div>
426
            )
427
          })}
428
      </div>
429
    </Modal >
430
  )
431
}
432
 
433
Chat.ContactsModal = ContactsModal
434
 
1 www 435
export default Chat;