Proyectos de Subversion LeadersLinked - Backend

Rev

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