Proyectos de Subversion LeadersLinked - Backend

Rev

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

Rev Autor Línea Nro. Línea
15834 stevensc 1
import React, { useEffect, useRef, useState } from "react";
15801 stevensc 2
import { axios } from "../../../utils";
15834 stevensc 3
import { useForm } from "react-hook-form";
11347 nelberth 4
 
5
import Emojione from "./emojione/Emojione";
6
import FileModal from "./fileModal/FileModal";
7
import Messages from "./messages/Messages";
15834 stevensc 8
import AttachFileIcon from "@mui/icons-material/AttachFile";
9
import InsertEmoticonIcon from "@mui/icons-material/InsertEmoticon";
15835 stevensc 10
import SendIcon from "@mui/icons-material/Send";
11347 nelberth 11
 
15834 stevensc 12
import styles from "./chat.module.scss";
13
 
11347 nelberth 14
const permittedFiles =
15
  "video/mp4, video/mpeg, video/webm, application/pdf, image/jpeg, image/png, image/jpg";
16
 
15834 stevensc 17
const Chat = ({ entity }) => {
11347 nelberth 18
  const [messages, setMessages] = useState([]);
19
  const [newMessages, setNewMessages] = useState([]);
20
  const [showEmojione, setShowEmojione] = useState(false);
21
  const [selectedFile, setSelectedFile] = useState("");
22
  const [pages, setPages] = useState(1);
23
  const [currentPage, setCurrentPage] = useState(1);
24
  const [oldMessages, setOldMessages] = useState([]);
15834 stevensc 25
  const [urlSearch, setUrlSearch] = useState("");
11347 nelberth 26
 
15834 stevensc 27
  const { handleSubmit, register } = useForm();
28
 
11347 nelberth 29
  const bottomToScroll = useRef(null);
30
  const inputTextEl = useRef(null);
31
  const fileInputEl = useRef(null);
32
  const loadMoreEl = useRef();
33
  const divToScroll = useRef(null);
15834 stevensc 34
 
35
  const {
36
    url_get_all_messages,
37
    url_send,
38
    url_upload,
39
    url_close,
40
    url_mark_seen,
41
    type,
42
  } = entity;
43
 
11347 nelberth 44
  let heartBeatInterval;
45
 
46
  useEffect(() => {
47
    clearInterval(heartBeatInterval);
48
    heartBeatInterval = setInterval(() => {
49
      chatHeartbeat();
50
    }, 800);
51
    return () => {
52
      clearInterval(heartBeatInterval);
53
    };
54
  }, [newMessages, oldMessages]);
55
 
56
  // infiniteScroll
57
  useEffect(() => {
58
    const options = {
59
      root: null,
60
      rootMargin: "0px",
61
      threshold: 1.0,
62
    };
63
    const observer = new IntersectionObserver(handleObserver, options);
64
    if (loadMoreEl.current) {
65
      observer.observe(loadMoreEl.current);
66
    }
67
    return () => {
68
      observer.disconnect();
69
    };
70
  }, [pages]);
71
 
72
  useEffect(() => {
73
    loadOldMessages();
74
  }, [currentPage]);
75
 
76
  useEffect(async () => {
77
    const resData = (await axios.post(url_mark_seen)).data;
15801 stevensc 78
    resData;
11347 nelberth 79
  }, []);
80
 
81
  // heartbeat function
82
  const chatHeartbeat = async () => {
83
    axios.get(url_get_all_messages).then((response) => {
84
      const resData = response.data;
15801 stevensc 85
      const isNewProp = url_get_all_messages !== urlSearch;
11347 nelberth 86
      if (resData.success) {
87
        const updatedNewMessages = resData.data.items.slice();
88
        let newNewMessages = [];
89
        updatedNewMessages.map((updatedNewMessage) => {
90
          const existInNewMessages = newMessages.findIndex(
91
            (newMessage) => newMessage.id === updatedNewMessage.id
92
          );
93
          if (existInNewMessages === -1) {
94
            newNewMessages = [updatedNewMessage, ...newNewMessages];
95
            setPages(resData.data.pages);
96
          }
97
        });
98
        if (newNewMessages.length > 0) {
99
          setNewMessages((prevState) => [...prevState, ...newNewMessages]);
100
        }
101
      }
102
    });
103
  };
104
 
105
  // utilsFunctions
106
  const scrollToBottom = () => {
15801 stevensc 107
    ("scrolled");
11347 nelberth 108
    const element = bottomToScroll.current;
109
    const divToScrollEl = divToScroll.current;
110
    divToScrollEl.scrollIntoView({ behavior: "smooth" });
111
  };
112
 
113
  const onClickEmoji = (event) => {
114
    const shortname = event.currentTarget.dataset.shortname;
115
    const currentText = inputTextEl.current.value;
116
    let cursorPosition = inputTextEl.current.selectionStart;
117
    const textBehind = currentText.substring(0, cursorPosition);
118
    const textForward = currentText.substring(cursorPosition);
119
    inputTextEl.current.value = `${textBehind}${shortname}${textForward}`;
120
    inputTextEl.current.focus();
121
    inputTextEl.current.setSelectionRange(
122
      cursorPosition + shortname.length,
123
      cursorPosition + shortname.length
124
    );
125
  };
126
 
127
  const handleUploadFile = (e) => {
128
    const file = e.target.files[0];
129
    if (file) {
130
      setSelectedFile(file);
131
    }
132
  };
133
 
134
  const removeSelectedFile = () => {
135
    setSelectedFile("");
136
  };
137
 
138
  const handleObserver = async (entities) => {
139
    const target = entities[0];
140
    if (target.isIntersecting) {
141
      if (currentPage < pages) {
142
        setCurrentPage((prevState) => prevState + 1);
143
        bottomToScroll.current.scrollBy(0, 200);
144
      }
145
    }
146
  };
147
 
148
  const loadOldMessages = async () => {
149
    if (currentPage < pages && currentPage > 1) {
150
    }
151
    await axios
152
      .get(url_get_all_messages, {
153
        params: {
154
          page: currentPage,
155
        },
156
      })
157
      .then(async (response) => {
158
        const resData = response.data;
159
        if (resData.success) {
160
          if (resData.data.page > 1) {
161
            setOldMessages([
162
              ...resData.data.items.slice().reverse(),
163
              ...oldMessages,
164
            ]);
165
          }
166
        }
167
      });
168
  };
169
 
170
  // on send message
171
  const onHandleSubmit = (data, event) => {
172
    const formData = new FormData();
173
    Object.entries(data).map(([key, value]) => {
174
      formData.append(key, value);
175
    });
176
    event.target.reset();
177
    axios.post(url_send, formData).then((response) => {
178
      setShowEmojione(false);
179
    });
180
  };
181
 
182
  // on send file
183
  const handleSendFile = () => {
184
    const formData = new FormData();
185
    formData.append("file", selectedFile);
186
    axios.post(url_upload, formData).then(async (response) => {
187
      const resData = response.data;
188
      if (resData.success) {
189
        setSelectedFile("");
190
        setShowEmojione(false);
191
      }
192
    });
193
  };
194
 
195
  return (
196
    <div className={styles.chat}>
197
      <div className={styles.messagesContainer} ref={bottomToScroll}>
198
        <div className={styles.messageWrapper}>
199
          {currentPage < pages && (
15834 stevensc 200
            <p ref={loadMoreEl} className="mt-2">
11347 nelberth 201
              Cargando...
202
            </p>
203
          )}
204
          <Messages
205
            oldMessages={oldMessages}
206
            newMessages={newMessages}
207
            onScrollToBottom={scrollToBottom}
208
            chatType={type}
209
          />
210
          <div ref={divToScroll}></div>
211
        </div>
212
      </div>
15805 stevensc 213
      <div className={styles.chat__input__container}>
11347 nelberth 214
        {showEmojione && <Emojione onClickEmoji={onClickEmoji} />}
215
        <form
216
          onSubmit={handleSubmit(onHandleSubmit)}
217
          encType="multipart/form-data"
218
        >
219
          <button
220
            type="button"
15836 stevensc 221
            className={"btn " + styles.icon_btn}
15833 stevensc 222
            onClick={() => fileInputEl.current.click()}
223
          >
224
            <AttachFileIcon />
225
          </button>
11347 nelberth 226
          <button
227
            type="button"
15836 stevensc 228
            className={"btn " + styles.icon_btn}
15833 stevensc 229
            onClick={() => setShowEmojione(!showEmojione)}
230
          >
231
            <InsertEmoticonIcon />
232
          </button>
11347 nelberth 233
          <input
234
            type="file"
15833 stevensc 235
            ref={(e) => (fileInputEl.current = e)}
11347 nelberth 236
            accept={permittedFiles}
15833 stevensc 237
            onChange={handleUploadFile}
11347 nelberth 238
            hidden
239
          />
240
          <textarea
241
            className={styles.chatInput}
242
            placeholder="Escribe un mensaje"
243
            rows="1"
244
            ref={inputTextEl}
15833 stevensc 245
          />
15836 stevensc 246
          <button type="submit" className={"btn " + styles.send_btn}>
15835 stevensc 247
            <SendIcon />
11347 nelberth 248
          </button>
249
        </form>
250
      </div>
251
      {selectedFile && (
252
        <FileModal
253
          file={selectedFile}
254
          onCancel={removeSelectedFile}
255
          onSend={handleSendFile}
256
        />
257
      )}
258
    </div>
259
  );
260
};
261
 
262
export default Chat;