Proyectos de Subversion LeadersLinked - Backend

Rev

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

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